<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>GCLI2API 控制面板</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 1000px;
            margin: 0 auto;
            padding: 20px;
            background-color: #f5f5f5;
        }

        .container {
            background-color: white;
            padding: 30px;
            border-radius: 10px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
        }

        h1 {
            color: #333;
            text-align: center;
        }

        .form-group {
            margin-bottom: 20px;
        }

        label {
            display: block;
            margin-bottom: 5px;
            font-weight: bold;
            color: #555;
        }

        input[type="text"] {
            width: 100%;
            padding: 10px;
            border: 2px solid #ddd;
            border-radius: 5px;
            font-size: 16px;
            box-sizing: border-box;
        }

        input[type="text"]:focus {
            border-color: #4285f4;
            outline: none;
        }

        .btn {
            background-color: #4285f4;
            color: white;
            padding: 12px 30px;
            border: none;
            border-radius: 5px;
            font-size: 16px;
            cursor: pointer;
            width: 100%;
            margin-bottom: 10px;
        }

        .btn:hover {
            background-color: #3367d6;
        }

        .btn:disabled {
            background-color: #ccc;
            cursor: not-allowed;
        }

        .auth-url {
            background-color: #f8f9fa;
            border: 1px solid #e1e4e8;
            border-radius: 5px;
            padding: 15px;
            margin: 20px 0;
            word-break: break-all;
        }

        .auth-url a {
            color: #4285f4;
            text-decoration: none;
        }

        .auth-url a:hover {
            text-decoration: underline;
        }

        .credentials {
            background-color: #f0f8ff;
            border: 1px solid #b0d4ff;
            border-radius: 5px;
            padding: 15px;
            margin: 20px 0;
            font-family: monospace;
            font-size: 12px;
            white-space: pre-wrap;
            word-break: break-all;
            max-height: 400px;
            overflow-y: auto;
        }

        .status {
            padding: 10px;
            border-radius: 5px;
            margin: 10px 0;
        }

        .status.success {
            background-color: #d4edda;
            border: 1px solid #c3e6cb;
            color: #155724;
        }

        .status.error {
            background-color: #f8d7da;
            border: 1px solid #f5c6cb;
            color: #721c24;
        }

        .status.info {
            background-color: #d1ecf1;
            border: 1px solid #bee5eb;
            color: #0c5460;
        }

        .hidden {
            display: none;
        }

        .loading {
            text-align: center;
            color: #666;
        }

        .login-form {
            text-align: center;
            padding: 50px 0;
        }

        .login-form input[type="password"] {
            width: 300px;
            padding: 12px;
            border: 2px solid #ddd;
            border-radius: 5px;
            font-size: 16px;
            margin-bottom: 20px;
            box-sizing: border-box;
        }

        .tabs {
            display: flex;
            border-bottom: 1px solid #ddd;
            margin-bottom: 20px;
        }

        .tab {
            padding: 10px 20px;
            cursor: pointer;
            border: none;
            background: #f5f5f5;
            border-bottom: 2px solid transparent;
        }

        .tab.active {
            background: white;
            border-bottom-color: #4285f4;
            color: #4285f4;
        }

        .tab-content {
            display: none;
        }

        .tab-content.active {
            display: block;
        }

        .upload-area {
            border: 2px dashed #ddd;
            border-radius: 5px;
            padding: 40px;
            text-align: center;
            background-color: #fafafa;
            margin: 20px 0;
            cursor: pointer;
            transition: border-color 0.3s;
        }

        .upload-area:hover {
            border-color: #4285f4;
        }

        .upload-area.dragover {
            border-color: #4285f4;
            background-color: #f0f8ff;
        }

        .file-list {
            margin: 20px 0;
        }

        .file-item {
            background-color: #f8f9fa;
            border: 1px solid #e1e4e8;
            border-radius: 3px;
            padding: 10px;
            margin: 5px 0;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .file-item .file-name {
            font-family: monospace;
            color: #333;
        }

        .file-item .file-size {
            color: #666;
            font-size: 12px;
        }

        .file-item .remove-btn {
            background: #dc3545;
            color: white;
            border: none;
            border-radius: 3px;
            padding: 2px 8px;
            cursor: pointer;
            font-size: 12px;
        }

        .upload-progress {
            background-color: #f8f9fa;
            border: 1px solid #e1e4e8;
            border-radius: 5px;
            padding: 15px;
            margin: 20px 0;
        }

        .progress-bar {
            width: 100%;
            height: 20px;
            background-color: #e9ecef;
            border-radius: 10px;
            overflow: hidden;
            margin: 10px 0;
        }

        .progress-fill {
            height: 100%;
            background-color: #28a745;
            transition: width 0.3s ease;
        }

        /* 文件管理样式 */
        .cred-card {
            background-color: #f8f9fa;
            border: 1px solid #e1e4e8;
            border-radius: 8px;
            padding: 15px;
            margin: 10px 0;
            position: relative;
            min-width: 600px;
        }

        .cred-card.disabled {
            background-color: #f5f5f5;
            border-color: #ccc;
            opacity: 0.7;
        }

        .cred-header {
            display: flex;
            justify-content: space-between;
            align-items: flex-start;
            margin-bottom: 10px;
            gap: 20px;
        }

        .cred-filename {
            font-family: monospace;
            font-weight: bold;
            color: #333;
            font-size: 14px;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            min-width: 300px;
        }

        .cred-status {
            display: flex;
            gap: 5px;
        }

        .status-badge {
            padding: 2px 8px;
            border-radius: 12px;
            font-size: 12px;
            color: white;
        }

        .status-badge.enabled {
            background-color: #28a745;
        }

        .status-badge.disabled {
            background-color: #6c757d;
        }

        .error-codes {
            background-color: #f8d7da;
            color: #721c24;
            padding: 2px 8px;
            border-radius: 12px;
            font-size: 12px;
        }

        .cred-actions {
            display: flex;
            gap: 5px;
            flex-wrap: wrap;
        }

        .cred-btn {
            padding: 4px 12px;
            border: none;
            border-radius: 4px;
            font-size: 12px;
            cursor: pointer;
            transition: background-color 0.2s;
        }

        .cred-btn.enable {
            background-color: #28a745;
            color: white;
        }

        .cred-btn.disable {
            background-color: #6c757d;
            color: white;
        }

        .cred-btn.delete {
            background-color: #dc3545;
            color: white;
        }

        .cred-btn.download {
            background-color: #007bff;
            color: white;
        }

        .cred-btn.view {
            background-color: #17a2b8;
            color: white;
        }

        .cred-details {
            margin-top: 10px;
            display: none;
        }

        .cred-details.show {
            display: block;
        }

        .cred-content {
            background-color: #f0f8ff;
            border: 1px solid #b0d4ff;
            border-radius: 4px;
            padding: 10px;
            font-family: monospace;
            font-size: 11px;
            white-space: pre-wrap;
            word-break: break-all;
            max-height: 200px;
            overflow-y: auto;
        }

        .manage-actions {
            margin-bottom: 20px;
            display: flex;
            gap: 10px;
            flex-wrap: wrap;
        }

        /* 文件管理新增样式 */
        .stats-container {
            display: flex;
            gap: 15px;
            margin-bottom: 20px;
            flex-wrap: wrap;
        }

        .stat-item {
            background: linear-gradient(45deg, #f8f9fa, #e9ecef);
            border: 1px solid #dee2e6;
            border-radius: 8px;
            padding: 12px 20px;
            text-align: center;
            min-width: 120px;
            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
        }

        .stat-number {
            font-size: 24px;
            font-weight: bold;
            color: #333;
            display: block;
        }

        .stat-label {
            font-size: 12px;
            color: #666;
            text-transform: uppercase;
            margin-top: 4px;
        }

        .stat-item.total {
            border-left: 4px solid #007bff;
        }

        .stat-item.normal {
            border-left: 4px solid #28a745;
        }

        .stat-item.disabled {
            border-left: 4px solid #6c757d;
        }

        .filter-container {
            display: flex;
            gap: 10px;
            margin-bottom: 20px;
            align-items: center;
            flex-wrap: wrap;
        }

        .filter-select {
            padding: 8px 12px;
            border: 2px solid #ddd;
            border-radius: 4px;
            font-size: 14px;
            background-color: white;
        }

        .filter-select:focus {
            border-color: #4285f4;
            outline: none;
        }

        .pagination-container {
            display: flex;
            justify-content: center;
            align-items: center;
            gap: 10px;
            margin: 20px 0;
            flex-wrap: wrap;
        }

        .pagination-info {
            color: #666;
            font-size: 14px;
        }

        .pagination-btn {
            padding: 8px 12px;
            border: 1px solid #ddd;
            background: white;
            cursor: pointer;
            border-radius: 4px;
            font-size: 14px;
        }

        .pagination-btn:hover:not(:disabled) {
            background: #f8f9fa;
            border-color: #4285f4;
        }

        .pagination-btn:disabled {
            background: #f5f5f5;
            color: #ccc;
            cursor: not-allowed;
        }

        .pagination-btn.active {
            background: #4285f4;
            color: white;
            border-color: #4285f4;
        }

        .page-size-select {
            padding: 6px 10px;
            border: 1px solid #ddd;
            border-radius: 4px;
            font-size: 14px;
        }

        .refresh-btn {
            background-color: #17a2b8;
            color: white;
            padding: 8px 16px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }

        .download-all-btn {
            background-color: #28a745;
            color: white;
            padding: 8px 16px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }

        /* 批量操作样式 */
        .batch-controls {
            background-color: #f8f9fa;
            border: 1px solid #e1e4e8;
            border-radius: 8px;
            padding: 15px;
            margin-bottom: 20px;
        }

        .checkbox-container {
            display: flex;
            align-items: center;
            margin-right: 15px;
        }

        .batch-actions {
            display: flex;
            gap: 10px;
            flex-wrap: wrap;
            align-items: center;
            margin-top: 10px;
        }

        .batch-btn {
            padding: 6px 12px;
            border: none;
            border-radius: 4px;
            font-size: 12px;
            cursor: pointer;
            transition: background-color 0.2s;
        }

        .batch-btn.batch-enable {
            background-color: #28a745;
            color: white;
        }

        .batch-btn.batch-disable {
            background-color: #6c757d;
            color: white;
        }

        .batch-btn.batch-delete {
            background-color: #dc3545;
            color: white;
        }

        .batch-btn.batch-email {
            background-color: #17a2b8;
            color: white;
        }

        .batch-btn:disabled {
            background-color: #e9ecef;
            color: #6c757d;
            cursor: not-allowed;
        }

        .cred-btn.email {
            background-color: #17a2b8;
            color: white;
        }

        .cred-btn.email:hover {
            background-color: #138496;
        }

        .selected-count {
            font-weight: bold;
            color: #007bff;
            margin-right: 10px;
        }

        .select-all-checkbox {
            margin-right: 8px;
            transform: scale(1.2);
        }

        /* 错误码筛选增强 */
        .error-filter-container {
            display: flex;
            gap: 10px;
            align-items: center;
            flex-wrap: wrap;
        }

        .error-code-badge {
            display: inline-block;
            background-color: #dc3545;
            color: white;
            padding: 2px 6px;
            border-radius: 10px;
            font-size: 11px;
            margin: 1px;
            cursor: pointer;
            transition: background-color 0.2s;
        }

        .error-code-badge:hover {
            background-color: #c82333;
        }

        .error-code-badge.selected {
            background-color: #007bff;
        }

        /* 配置管理样式 */
        .config-group {
            background-color: #f8f9fa;
            border: 1px solid #e1e4e8;
            border-radius: 8px;
            padding: 20px;
            margin: 15px 0;
        }

        .config-group h4 {
            margin-top: 0;
            margin-bottom: 15px;
            color: #333;
            border-bottom: 1px solid #e1e4e8;
            padding-bottom: 8px;
        }

        .config-input {
            width: 100%;
            padding: 8px 12px;
            border: 2px solid #ddd;
            border-radius: 4px;
            font-size: 14px;
            box-sizing: border-box;
            margin-bottom: 5px;
        }

        .config-input:focus {
            border-color: #4285f4;
            outline: none;
        }

        .config-input:disabled {
            background-color: #f5f5f5;
            color: #666;
            cursor: not-allowed;
        }

        .config-checkbox {
            margin-right: 8px;
            transform: scale(1.2);
        }

        .config-note {
            display: block;
            color: #666;
            font-size: 12px;
            margin-bottom: 10px;
            font-style: italic;
        }

        .config-info {
            background-color: #e3f2fd;
            border: 1px solid #1976d2;
            border-radius: 4px;
            padding: 12px;
            margin-top: 8px;
            font-size: 13px;
            color: #1565c0;
        }

        .config-info ul {
            margin: 8px 0 4px 0;
            color: #424242;
        }

        .config-info li {
            margin: 3px 0;
        }

        .env-locked {
            position: relative;
        }

        .env-locked::after {
            content: "🔒 环境变量锚定";
            position: absolute;
            right: 10px;
            top: 50%;
            transform: translateY(-50%);
            background-color: #ffc107;
            color: #212529;
            padding: 2px 6px;
            border-radius: 3px;
            font-size: 11px;
            pointer-events: none;
        }

        /* 使用统计样式 */
        .usage-card {
            background-color: #f8f9fa;
            border: 1px solid #e1e4e8;
            border-radius: 8px;
            padding: 15px;
            margin: 10px 0;
            position: relative;
        }

        .usage-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 15px;
        }

        .usage-filename {
            font-family: monospace;
            font-weight: bold;
            color: #333;
            font-size: 14px;
        }

        .usage-progress {
            margin: 10px 0;
        }

        .usage-progress-label {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 5px;
            font-size: 12px;
        }

        .usage-progress-bar {
            width: 100%;
            height: 20px;
            background-color: #e9ecef;
            border-radius: 10px;
            overflow: hidden;
            position: relative;
        }

        .usage-progress-fill {
            height: 100%;
            transition: width 0.3s ease;
        }

        .usage-progress-fill.gemini {
            background-color: #ff6b35;
        }

        .usage-progress-fill.total {
            background-color: #007bff;
        }

        .usage-progress-fill.warning {
            background-color: #ffc107;
        }

        .usage-progress-fill.danger {
            background-color: #dc3545;
        }

        .usage-actions {
            display: flex;
            gap: 5px;
            margin-top: 10px;
        }

        .usage-btn {
            padding: 4px 8px;
            border: none;
            border-radius: 4px;
            font-size: 11px;
            cursor: pointer;
            transition: background-color 0.2s;
        }

        .usage-btn.reset {
            background-color: #6c757d;
            color: white;
        }

        .usage-btn.limits {
            background-color: #17a2b8;
            color: white;
        }

        .usage-info {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 10px;
            margin-top: 10px;
            font-size: 12px;
        }

        .usage-info-item {
            background-color: #ffffff;
            padding: 8px;
            border-radius: 4px;
            border: 1px solid #dee2e6;
        }

        .usage-info-label {
            font-weight: bold;
            color: #666;
            display: block;
            margin-bottom: 2px;
        }

        .usage-info-value {
            color: #333;
        }

        .reset-time {
            font-size: 11px;
            color: #666;
            font-style: italic;
            margin-top: 5px;
        }

        /* 限制设置弹窗样式 */
        .modal {
            display: none;
            position: fixed;
            z-index: 1000;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.5);
        }

        .modal-content {
            background-color: #fefefe;
            margin: 15% auto;
            padding: 20px;
            border-radius: 8px;
            width: 400px;
            max-width: 90%;
        }

        .modal-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 15px;
            padding-bottom: 10px;
            border-bottom: 1px solid #dee2e6;
        }

        .modal-title {
            margin: 0;
            font-size: 16px;
            color: #333;
        }

        .modal-close {
            background: none;
            border: none;
            font-size: 20px;
            cursor: pointer;
            color: #999;
        }

        .modal-close:hover {
            color: #333;
        }

        .modal-body {
            margin-bottom: 15px;
        }

        .modal-footer {
            display: flex;
            gap: 10px;
            justify-content: flex-end;
        }
    </style>
</head>

<body>
    <div class="container">

        <!-- 登录界面 -->
        <div id="loginSection" class="login-form">
            <h1>GCLI2API 管理面板</h1>
            <p>请输入访问密码：</p>
            <input type="password" id="loginPassword" placeholder="输入密码" onkeypress="handlePasswordEnter(event)" />
            <br>
            <button class="btn" onclick="login()">登录</button>
        </div>

        <!-- 主界面 -->
        <div id="mainSection" class="hidden">
            <h1>GCLI2API 管理面板</h1>

            <!-- 标签页 -->
            <div class="tabs">
                <button class="tab active" onclick="switchTab('oauth')">OAuth认证</button>
                <button class="tab" onclick="switchTab('upload')">批量上传</button>
                <button class="tab" onclick="switchTab('envload')">环境变量</button>
                <button class="tab" onclick="switchTab('manage')">文件管理</button>
                <button class="tab" onclick="switchTab('usage')">使用统计</button>
                <button class="tab" onclick="switchTab('config')">配置管理</button>
                <button class="tab" onclick="switchTab('logs')">实时日志</button>
                <button class="tab" onclick="switchTab('about')">项目信息</button>
            </div>

            <!-- OAuth认证标签页 -->
            <div id="oauthTab" class="tab-content active">
                <!-- API 自动启用说明 -->
                <div class="status success" style="margin-bottom: 20px;">
                    <strong>✨ 自动化优化：</strong> 系统现在会在认证成功后自动为您的项目启用必需的API服务
                    <ul style="margin: 10px 0; padding-left: 20px;">
                        <li><strong>Gemini Cloud Assist API</strong></li>
                        <li><strong>Gemini for Google Cloud API</strong></li>
                    </ul>
                    <p style="margin: 10px 0; color: #155724;"><strong>说明：</strong>无需手动启用API，系统会自动处理这些配置步骤，让认证流程更加顺畅。
                    </p>
                </div>

                <!-- 折叠式 Project ID 输入框 -->
                <div class="form-group">
                    <div style="cursor: pointer; user-select: none; padding: 12px; border: 2px solid #ddd; border-radius: 5px; background: #f8f9fa; display: flex; justify-content: space-between; align-items: center;"
                        onclick="toggleProjectIdSection()">
                        <span style="font-weight: bold; color: #555;">📁 高级选项：Google Cloud Project ID
                            (不用管，直接点击获取链接即可)</span>
                        <span id="projectIdToggleIcon"
                            style="font-size: 14px; color: #666; transition: transform 0.3s ease;">▶</span>
                    </div>
                    <div id="projectIdSection"
                        style="display: none; margin-top: 15px; padding: 15px; border: 2px solid #ddd; border-top: none; border-radius: 0 0 5px 5px; background: #ffffff;">
                        <label for="projectId"
                            style="display: block; margin-bottom: 5px; font-weight: bold; color: #555;">Google Cloud
                            Project ID (可选):</label>
                        <input type="text" id="projectId"
                            style="width: 100%; padding: 10px; border: 2px solid #ddd; border-radius: 5px; font-size: 16px; box-sizing: border-box;"
                            placeholder="留空将尝试自动检测，或手动输入项目ID" />
                        <small style="color: #666; font-size: 12px; margin-top: 5px; display: block;">
                            💡 提示：如果你不懂这是什么，可以留空此字段让系统自动检测项目ID
                        </small>
                    </div>
                </div>

                <!-- 为所有项目获取凭证选项 -->
                <div class="form-group">
                    <div style="padding: 15px; border: 2px solid #28a745; border-radius: 8px; background: #f8fff9;">
                        <div style="display: flex; align-items: center; gap: 12px;">
                            <input type="checkbox" id="getAllProjectsCreds" style="transform: scale(1.3);">
                            <label for="getAllProjectsCreds"
                                style="font-weight: bold; color: #28a745; margin: 0; cursor: pointer;">
                                🌐 为当前账号所有项目获取凭证
                            </label>
                        </div>
                        <div style="margin-top: 10px; color: #155724; font-size: 14px; line-height: 1.5;">
                            <strong>说明：</strong>勾选此选项后，系统会自动检测当前Google账号下的所有项目，<strong>并发处理</strong>为每个项目生成独立的认证文件。
                        </div>
                        <div id="allProjectsNote"
                            style="margin-top: 8px; padding: 8px; background: #d4edda; border-radius: 5px; font-size: 13px; color: #155724; display: none;">
                            ✨ <strong>批量并发认证模式已启用</strong> - 认证完成后将并发为所有可访问的项目生成凭证文件
                        </div>
                    </div>
                </div>

                <button class="btn" id="getAuthBtn" onclick="startAuth()">获取认证链接</button>

                <div id="authUrlSection" class="hidden">
                    <h3>认证链接：</h3>
                    <div class="auth-url">
                        <a id="authUrl" href="#" target="_blank">点击此链接进行认证</a>
                    </div>
                    <div class="status info">
                        <strong>重要说明：</strong>
                        <ol style="margin: 10px 0; padding-left: 20px;">
                            <li>点击上方认证链接，会在新窗口中打开Google OAuth页面</li>
                            <li>完成Google账号登录和授权</li>
                            <li>授权成功后会跳转到localhost:8080显示成功页面</li>
                            <li>关闭OAuth窗口，返回本页面</li>
                            <li>点击下方"获取认证文件"按钮完成流程</li>
                        </ol>
                    </div>

                    <!-- 快捷回调URL输入选项 -->
                    <div class="form-group"
                        style="margin: 20px 0; padding: 15px; border: 2px solid #e8f4fd; border-radius: 8px; background: #f8fcff;">
                        <div style="cursor: pointer; user-select: none; display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;"
                            onclick="toggleCallbackUrlSection()">
                            <span style="font-weight: bold; color: #0066cc;">🚀 无法回源？试试快捷方式</span>
                            <span id="callbackUrlToggleIcon"
                                style="font-size: 14px; color: #666; transition: transform 0.3s ease;">▼</span>
                        </div>
                        <div id="callbackUrlSection" style="display: none;">
                            <div
                                style="background: #fff3cd; border: 1px solid #ffeaa7; border-radius: 6px; padding: 12px; margin-bottom: 12px;">
                                <div style="color: #856404; font-size: 14px; font-weight: bold; margin-bottom: 6px;">📚
                                    适用场景：</div>
                                <ul
                                    style="color: #856404; font-size: 13px; margin: 0; padding-left: 18px; line-height: 1.5;">
                                    <li>云服务器、VPS等非本地环境</li>
                                    <li>防火墙阻止了8080端口访问</li>
                                    <li>网络环境无法正常回源到localhost</li>
                                    <li>Docker容器内运行，端口映射问题</li>
                                </ul>
                            </div>
                            <div style="color: #666; font-size: 13px; margin-bottom: 12px; line-height: 1.6;">
                                <strong style="color: #0066cc;">🔍 什么是回调URL？</strong><br>
                                完成Google OAuth授权后，浏览器地址栏显示的完整URL，通常看起来像这样：<br>
                                <code
                                    style="background: #f1f3f4; padding: 2px 6px; border-radius: 3px; font-size: 12px; word-break: break-all;">
                                    http://localhost:8080/?state=abc123...&code=4/0AVMBsJ...&scope=email%20profile...
                                </code>
                            </div>
                            <div
                                style="background: #e7f3ff; border: 1px solid #b3d9ff; border-radius: 6px; padding: 10px; margin-bottom: 12px;">
                                <div style="color: #0066cc; font-size: 13px; font-weight: bold; margin-bottom: 4px;">📋
                                    使用步骤：</div>
                                <ol
                                    style="color: #0066cc; font-size: 12px; margin: 0; padding-left: 18px; line-height: 1.4;">
                                    <li>点击上方认证链接，完成Google授权</li>
                                    <li>授权成功后，复制浏览器地址栏的<strong>完整URL</strong></li>
                                    <li>粘贴到下方输入框，点击获取凭证即可</li>
                                </ol>
                            </div>
                            <div class="input-group">
                                <input type="url" id="callbackUrlInput"
                                    placeholder="粘贴完整的回调URL，例如：http://localhost:8080/?state=xxx&code=xxx&scope=xxx..."
                                    style="width: 100%; padding: 10px; border: 2px solid #ddd; border-radius: 4px; font-size: 13px;">
                            </div>
                            <button class="btn" style="margin-top: 10px; background: #28a745; border-color: #28a745;"
                                onclick="processCallbackUrl()">
                                从回调URL获取凭证
                            </button>
                        </div>
                    </div>

                    <button class="btn" id="getCredsBtn" onclick="getCredentials()">获取认证文件</button>
                </div>

                <div id="credentialsSection" class="hidden">
                    <h3>认证文件内容：</h3>
                    <div class="credentials" id="credentialsContent"></div>
                </div>
            </div>

            <!-- 批量上传标签页 -->
            <div id="uploadTab" class="tab-content">
                <h3>批量上传认证文件</h3>
                <p>支持上传多个JSON格式的认证文件到服务器</p>

                <div class="upload-area" id="uploadArea" onclick="document.getElementById('fileInput').click()">
                    <p>点击选择文件或拖拽文件到此区域</p>
                    <p style="color: #666; font-size: 14px;">支持 .json 和 .zip 格式文件</p>
                    <p style="color: #888; font-size: 12px;">ZIP文件会自动解压提取其中的JSON凭证</p>
                </div>

                <input type="file" id="fileInput" multiple accept=".json,.zip" style="display: none;"
                    onchange="handleFileSelect(event)" />

                <div id="fileListSection" class="hidden">
                    <h4>选择的文件：</h4>
                    <div class="file-list" id="fileList"></div>
                    <button class="btn" onclick="uploadFiles()">上传文件</button>
                    <button class="btn" style="background-color: #6c757d;" onclick="clearFiles()">清空列表</button>
                </div>

                <div id="uploadProgressSection" class="hidden">
                    <div class="upload-progress">
                        <h4>上传进度：</h4>
                        <div class="progress-bar">
                            <div class="progress-fill" id="progressFill" style="width: 0%"></div>
                        </div>
                        <p id="progressText">0%</p>
                    </div>
                </div>
            </div>

            <!-- 环境变量标签页 -->
            <div id="envloadTab" class="tab-content">
                <h3>环境变量凭证导入</h3>
                <p>从环境变量批量导入认证文件，支持部署自动化场景</p>

                <!-- 环境变量状态信息 -->
                <div id="envStatusSection">
                    <div class="loading" id="envStatusLoading">正在检查环境变量状态...</div>
                    <div id="envStatusContent" class="hidden">
                        <div class="config-group">
                            <h4>环境变量状态</h4>

                            <div class="form-group">
                                <label>可用的环境变量:</label>
                                <div id="envVarsList" class="cred-content"></div>
                            </div>

                            <div class="form-group">
                                <label>自动加载设置:</label>
                                <span id="autoLoadStatus" style="font-weight: bold;"></span>
                                <small class="config-note">
                                    要启用自动加载，请设置环境变量 AUTO_LOAD_ENV_CREDS=true
                                </small>
                            </div>

                            <div class="form-group">
                                <label>已导入的环境变量文件:</label>
                                <span id="envFilesCount" style="font-weight: bold;"></span>
                                <div id="envFilesList" class="config-note"></div>
                            </div>
                        </div>
                    </div>
                </div>

                <!-- 操作按钮 -->
                <div class="manage-actions">
                    <button class="btn" onclick="checkEnvCredsStatus()">刷新状态</button>
                    <button class="btn" onclick="loadEnvCredentials()">从环境变量导入</button>
                    <button class="btn" style="background-color: #dc3545;"
                        onclick="clearEnvCredentials()">清除环境变量文件</button>
                </div>

                <!-- 使用说明 -->
                <div class="config-group">
                    <h4>使用说明</h4>
                    <div class="config-info">
                        <strong>环境变量格式：</strong>
                        <ul>
                            <li><code>GCLI_CREDS_1</code>, <code>GCLI_CREDS_2</code>, ... (编号格式)</li>
                            <li><code>GCLI_CREDS_项目名1</code>, <code>GCLI_CREDS_项目名2</code>, ... (项目名格式)</li>
                        </ul>

                        <strong>环境变量值：</strong> 完整的认证文件JSON内容

                        <br><br>
                        <strong>示例：</strong>
                        <pre style="background: #f8f9fa; padding: 10px; border-radius: 4px; font-size: 11px;">
export GCLI_CREDS_1='{"client_id":"your-client-id","client_secret":"your-secret","refresh_token":"your-token","token_uri":"https://oauth2.googleapis.com/token","project_id":"your-project"}'
export GCLI_CREDS_myproject='{"client_id":"...","project_id":"myproject",...}'
export AUTO_LOAD_ENV_CREDS=true  # 启用程序启动时自动导入</pre>

                        <strong>Docker部署示例：</strong>
                        <pre style="background: #f8f9fa; padding: 10px; border-radius: 4px; font-size: 11px;">
docker run -e GCLI_CREDS_1='{"client_id":"..."}' \
           -e AUTO_LOAD_ENV_CREDS=true \
           your-image</pre>
                    </div>
                </div>
            </div>

            <!-- 文件管理标签页 -->
            <div id="manageTab" class="tab-content">
                <h3>凭证文件管理</h3>
                <p>管理所有认证文件，查看状态和执行操作</p>

                <!-- 状态统计 -->
                <div class="stats-container" id="statsContainer">
                    <div class="stat-item total">
                        <span class="stat-number" id="statTotal">0</span>
                        <span class="stat-label">总计</span>
                    </div>
                    <div class="stat-item normal">
                        <span class="stat-number" id="statNormal">0</span>
                        <span class="stat-label">正常</span>
                    </div>
                    <div class="stat-item disabled">
                        <span class="stat-number" id="statDisabled">0</span>
                        <span class="stat-label">禁用</span>
                    </div>
                </div>

                <div class="manage-actions">
                    <button class="refresh-btn" onclick="refreshCredsStatus()">刷新状态</button>
                    <button class="download-all-btn" onclick="downloadAllCreds()">打包下载所有文件</button>
                </div>

                <!-- 批量操作控件 -->
                <div class="batch-controls">
                    <h4 style="margin-top: 0; margin-bottom: 10px;">批量操作</h4>
                    <div class="batch-actions">
                        <div class="checkbox-container">
                            <input type="checkbox" id="selectAllCheckbox" class="select-all-checkbox"
                                onchange="toggleSelectAll()">
                            <label for="selectAllCheckbox">全选</label>
                        </div>
                        <span class="selected-count" id="selectedCount">已选择 0 项</span>
                        <button class="batch-btn batch-enable" id="batchEnableBtn" onclick="batchAction('enable')"
                            disabled>批量启用</button>
                        <button class="batch-btn batch-disable" id="batchDisableBtn" onclick="batchAction('disable')"
                            disabled>批量禁用</button>
                        <button class="batch-btn batch-delete" id="batchDeleteBtn" onclick="batchAction('delete')"
                            disabled>批量删除</button>
                        <button class="batch-btn batch-email" onclick="refreshAllEmails()">刷新所有邮箱</button>
                    </div>
                </div>

                <!-- 筛选和分页控件 -->
                <div class="filter-container">
                    <label for="statusFilter">状态筛选：</label>
                    <select id="statusFilter" class="filter-select" onchange="applyFilters()">
                        <option value="all">全部</option>
                        <option value="normal">正常</option>
                        <option value="disabled">禁用</option>
                    </select>

                    <label for="errorCodeFilter">错误码筛选：</label>
                    <select id="errorCodeFilter" class="filter-select" onchange="applyFilters()">
                        <option value="all">全部错误码</option>
                        <option value="no-errors">无错误</option>
                        <option value="has-errors">有错误</option>
                        <option value="400">错误码 400</option>
                        <option value="401">错误码 401</option>
                        <option value="403">错误码 403</option>
                        <option value="404">错误码 404</option>
                        <option value="429">错误码 429</option>
                        <option value="500">错误码 500</option>
                    </select>

                    <label for="pageSizeSelect">每页显示：</label>
                    <select id="pageSizeSelect" class="page-size-select" onchange="changePageSize()">
                        <option value="20">20</option>
                        <option value="50">50</option>
                        <option value="100">100</option>
                    </select>

                    <div class="error-filter-container" id="errorFilterContainer">
                        <span>快速筛选错误码：</span>
                        <div id="errorCodeBadges"></div>
                    </div>
                </div>

                <div id="credsListSection">
                    <div class="loading" id="credsLoading">正在加载凭证文件...</div>
                    <div id="credsList"></div>

                    <!-- 分页控件 -->
                    <div class="pagination-container" id="paginationContainer" style="display: none;">
                        <button class="pagination-btn" id="prevPageBtn" onclick="changePage(-1)">上一页</button>
                        <div class="pagination-info" id="paginationInfo">第 1 页，共 1 页</div>
                        <button class="pagination-btn" id="nextPageBtn" onclick="changePage(1)">下一页</button>
                    </div>
                </div>
            </div>

            <!-- 使用统计标签页 -->
            <div id="usageTab" class="tab-content">
                <h3>使用统计</h3>
                <p>查看每个凭证文件的API调用统计和配额使用情况</p>

                <!-- 统计概览 -->
                <div class="stats-container" id="usageStatsContainer">
                    <div class="stat-item total">
                        <span class="stat-number" id="totalApiCalls">0</span>
                        <span class="stat-label">总调用数</span>
                    </div>
                    <div class="stat-item normal" style="border-left: 4px solid #ff6b35;">
                        <span class="stat-number" id="geminiProCalls">0</span>
                        <span class="stat-label">Gemini 2.5 Pro</span>
                    </div>
                    <div class="stat-item disabled">
                        <span class="stat-number" id="totalFiles">0</span>
                        <span class="stat-label">活跃文件数</span>
                    </div>
                </div>

                <div class="manage-actions">
                    <button class="refresh-btn" onclick="refreshUsageStats()">刷新统计</button>
                    <button class="btn" style="background-color: #dc3545;"
                        onclick="resetAllUsageStats()">重置所有统计</button>
                </div>

                <!-- 文件使用统计列表 -->
                <div id="usageListSection">
                    <div class="loading" id="usageLoading">正在加载使用统计...</div>
                    <div id="usageList"></div>
                </div>

                <!-- 使用说明 -->
                <div class="config-group">
                    <h4>使用说明</h4>
                    <div class="config-info">
                        <strong>统计范围：</strong>
                        <ul>
                            <li><strong>Gemini 2.5 Pro 调用次数：</strong>仅统计 gemini-2.5-pro 及其变体模型的成功调用</li>
                            <li><strong>所有模型调用次数：</strong>统计所有模型的成功调用总数</li>
                            <li><strong>每日配额：</strong>默认每日配额 Gemini 2.5 Pro: 100次，所有模型: 1000次</li>
                            <li><strong>配额重置：</strong>每天 UTC 07:00 自动重置调用计数</li>
                        </ul>

                        <strong>注意：</strong>
                        <ul>
                            <li>只统计返回正常响应的API调用，报错的调用不计入统计</li>
                            <li>统计数据持久化保存在 creds_state.toml 文件中</li>
                            <li>支持每个凭证文件独立统计和配额管理</li>
                        </ul>
                    </div>
                </div>
            </div>

            <!-- 配置管理标签页 -->
            <div id="configTab" class="tab-content">
                <h3>配置管理</h3>
                <p>管理系统配置参数，修改后立即生效</p>

                <div class="manage-actions">
                    <button class="refresh-btn" onclick="loadConfig()">刷新配置</button>
                    <button class="btn" onclick="saveConfig()">保存配置</button>
                </div>

                <div id="configSection">
                    <div class="loading" id="configLoading">正在加载配置...</div>
                    <div id="configForm" class="hidden">
                        <div class="config-group">
                            <h4>服务器配置</h4>

                            <div class="form-group">
                                <label for="host">服务器主机地址:</label>
                                <input type="text" id="host" class="config-input"
                                    placeholder="例如: 0.0.0.0, 127.0.0.1" />
                                <small class="config-note">服务器监听的主机地址，0.0.0.0表示监听所有接口</small>
                            </div>

                            <div class="form-group">
                                <label for="port">服务器端口:</label>
                                <input type="number" id="port" class="config-input" min="1" max="65535"
                                    placeholder="7861" />
                                <small class="config-note">服务器监听的端口号，修改后需要重启服务器</small>
                            </div>

                            <div class="form-group">
                                <label for="configApiPassword">API访问密码:</label>
                                <input type="text" id="configApiPassword" class="config-input" placeholder="pwd" />
                                <small class="config-note">聊天API访问密码，用于OpenAI和Gemini API端点的认证</small>
                            </div>

                            <div class="form-group">
                                <label for="configPanelPassword">控制面板密码:</label>
                                <input type="text" id="configPanelPassword" class="config-input" placeholder="pwd" />
                                <small class="config-note">控制面板访问密码，用于web界面登录认证</small>
                            </div>

                            <div class="form-group">
                                <label for="configPassword">通用密码:</label>
                                <input type="text" id="configPassword" class="config-input" placeholder="pwd" />
                                <small class="config-note">（兼容性保留）设置后将覆盖上述两个密码，留空则使用分开的密码设置</small>
                            </div>
                        </div>

                        <div class="config-group">
                            <h4>基础配置</h4>

                            <div class="form-group">
                                <label for="credentialsDir">凭证目录路径:</label>
                                <input type="text" id="credentialsDir" class="config-input" />
                                <small class="config-note">存储认证文件的目录路径</small>
                            </div>

                            <div class="form-group">
                                <label for="proxy">代理设置:</label>
                                <input type="text" id="proxy" class="config-input"
                                    placeholder="例如: http://proxy:8080 或 socks5://proxy:1080" />
                                <small class="config-note">HTTP/HTTPS/SOCKS5Endpoint，留空表示不使用代理</small>
                            </div>
                        </div>

                        <div class="config-group">
                            <h4>端点配置</h4>

                            <!-- 快速配置按钮 -->
                            <div class="form-group">
                                <div style="display: flex; gap: 10px; margin-bottom: 15px; flex-wrap: wrap;">
                                    <button type="button" class="btn" onclick="useMirrorUrls()"
                                        style="background-color: #28a745; font-size: 14px;">
                                        🚀 一键使用镜像网址
                                    </button>
                                    <button type="button" class="btn" onclick="restoreOfficialUrls()"
                                        style="background-color: #17a2b8; font-size: 14px;">
                                        🔄 还原官方端点
                                    </button>
                                </div>
                                <small class="config-note">镜像网址主要解决墙内无法访问官方端点的问题，部分地区可能无法使用</small>
                            </div>

                            <div class="form-group">
                                <label for="codeAssistEndpoint">Code Assist Endpoint:</label>
                                <input type="text" id="codeAssistEndpoint" class="config-input" />
                                <small class="config-note">Google Cloud Code Assist API端点地址</small>
                            </div>
                            <div class="form-group">
                                <label for="oauthProxyUrl">OAuth Endpoint:</label>
                                <input type="text" id="oauthProxyUrl" class="config-input"
                                    placeholder="https://oauth2.googleapis.com" />
                                <small class="config-note">Google OAuth2 API端点地址，用于token获取和刷新</small>
                            </div>
                            <div class="form-group">
                                <label for="googleapisProxyUrl">Google APIs Endpoint:</label>
                                <input type="text" id="googleapisProxyUrl" class="config-input"
                                    placeholder="https://www.googleapis.com" />
                                <small class="config-note">Google APIs API端点地址，用于API服务调用</small>
                            </div>
                            <div class="form-group">
                                <label for="resourceManagerApiUrl">Resource Manager API Endpoint:</label>
                                <input type="text" id="resourceManagerApiUrl" class="config-input"
                                    placeholder="https://cloudresourcemanager.googleapis.com" />
                                <small class="config-note">Google Cloud Resource Manager API端点地址，用于项目管理</small>
                            </div>
                            <div class="form-group">
                                <label for="serviceUsageApiUrl">Service Usage API Endpoint:</label>
                                <input type="text" id="serviceUsageApiUrl" class="config-input"
                                    placeholder="https://serviceusage.googleapis.com" />
                                <small class="config-note">Google Cloud Service Usage API端点地址，用于服务启用管理</small>
                            </div>
                        </div>

                        <div class="config-group">
                            <h4>自动封禁配置</h4>

                            <div class="form-group">
                                <label>
                                    <input type="checkbox" id="autoBanEnabled" class="config-checkbox" />
                                    启用自动封禁
                                </label>
                                <small class="config-note">遇到指定错误码时自动禁用凭证</small>
                            </div>

                            <div class="form-group">
                                <label for="autoBanErrorCodes">自动封禁错误码:</label>
                                <input type="text" id="autoBanErrorCodes" class="config-input"
                                    placeholder="例如: 400,403" />
                                <small class="config-note">用逗号分隔的错误码列表</small>
                            </div>
                        </div>

                        <div class="config-group">
                            <h4>性能配置</h4>

                            <div class="form-group">
                                <label for="callsPerRotation">凭证轮换调用次数:</label>
                                <input type="number" id="callsPerRotation" class="config-input" min="1" max="100" />
                                <small class="config-note">每个凭证使用多少次后轮换到下一个</small>
                            </div>

                        </div>

                        <div class="config-group">
                            <h4>429重试配置</h4>

                            <div class="form-group">
                                <label>
                                    <input type="checkbox" id="retry429Enabled" class="config-checkbox" />
                                    启用429重试
                                </label>
                                <small class="config-note">遇到429错误时自动重试</small>
                            </div>

                            <div class="form-group">
                                <label for="retry429MaxRetries">429重试次数:</label>
                                <input type="number" id="retry429MaxRetries" class="config-input" min="1" max="50" />
                                <small class="config-note">遇到429错误时的最大重试次数</small>
                            </div>

                            <div class="form-group">
                                <label for="retry429Interval">429重试间隔(秒):</label>
                                <input type="number" id="retry429Interval" class="config-input" min="0.01" max="10"
                                    step="0.01" />
                                <small class="config-note">遇到429错误时每两次重试间的等待时间</small>
                            </div>
                        </div>


                        <div class="config-group">
                            <h4>兼容性配置</h4>

                            <div class="form-group">
                                <label>
                                    <input type="checkbox" id="compatibilityModeEnabled" class="config-checkbox" />
                                    启用兼容性模式
                                </label>
                                <small class="config-note">启用后所有system消息全部转换成user，停用system_instructions <span
                                        style="color: #28a745;">✓ 支持热更新</span></small>
                                <div class="config-info"
                                    style="background-color: #fff3cd; border: 1px solid #ffc107; color: #856404;">
                                    <strong>⚠️ 注意：</strong>该选项可能会降低模型理解能力，但是能避免流式空回的情况。
                                    <br><strong>适用场景：</strong>当遇到流式传输时模型不返回内容或返回空响应时启用此选项。
                                </div>
                            </div>
                        </div>

                        <div class="config-group">
                            <h4>抗截断配置</h4>

                            <div class="form-group">
                                <label for="antiTruncationMaxAttempts">抗截断最大重试次数:</label>
                                <input type="number" id="antiTruncationMaxAttempts" class="config-input" min="1"
                                    max="10" />
                                <small class="config-note">当检测到输出截断时的最大续传尝试次数</small>
                            </div>

                            <div class="form-group">
                                <div class="config-info">
                                    <strong>注意：</strong>抗截断功能现在通过模型名控制：
                                    <ul style="margin: 5px 0; padding-left: 20px;">
                                        <li>选择带有 "-流式抗截断" 后缀的模型即可启用</li>
                                        <li>该功能仅在流式传输时生效</li>
                                        <li>例如: "gemini-2.5-pro-流式抗截断"</li>
                                    </ul>
                                </div>
                            </div>
                        </div>

                        <div class="config-group">
                            <h4>配置热更新说明</h4>

                            <div class="form-group">
                                <div class="config-info"
                                    style="background-color: #d4edda; border: 1px solid #c3e6cb; color: #155724;">
                                    <strong>🔥 热更新配置（立即生效）：</strong>
                                    <ul style="margin: 8px 0; padding-left: 20px; color: #212529;">
                                        <li><strong>网络配置：</strong>代理设置、端点配置、HTTP超时时间、最大连接数</li>
                                        <li><strong>API配置：</strong>凭证轮换次数、429重试设置、自动封禁配置</li>
                                        <li><strong>密码配置：</strong>API密码、控制面板密码、通用密码</li>
                                        <li><strong>功能配置：</strong>抗截断最大重试次数</li>
                                    </ul>
                                </div>
                            </div>

                            <div class="form-group">
                                <div class="config-info"
                                    style="background-color: #fff3cd; border: 1px solid #ffc107; color: #856404;">
                                    <strong>🔄 需要重启的配置：</strong>
                                    <ul style="margin: 8px 0; padding-left: 20px; color: #212529;">
                                        <li><strong>服务器配置：</strong>主机地址、端口号</li>
                                        <li><strong>目录配置：</strong>凭证目录路径、Code Assist端点</li>
                                    </ul>
                                </div>
                            </div>

                        </div>
                    </div>
                </div>
            </div>

            <!-- 实时日志标签页 -->
            <div id="logsTab" class="tab-content">
                <h3>实时日志</h3>
                <p>查看系统实时日志输出，支持日志筛选和自动滚动</p>

                <div class="manage-actions">
                    <button class="refresh-btn" onclick="connectWebSocket()">连接日志流</button>
                    <button class="btn" style="background-color: #dc3545;" onclick="disconnectWebSocket()">断开连接</button>
                    <button class="btn" style="background-color: #28a745;" onclick="downloadLogs()">下载日志</button>
                    <button class="btn" style="background-color: #6c757d;" onclick="clearLogs()">清空日志</button>
                </div>

                <div class="filter-container">
                    <label for="logLevelFilter">日志级别筛选：</label>
                    <select id="logLevelFilter" class="filter-select" onchange="filterLogs()">
                        <option value="all">全部</option>
                        <option value="ERROR">错误</option>
                        <option value="WARNING">警告</option>
                        <option value="INFO">信息</option>
                        <option value="DEBUG">调试</option>
                    </select>

                    <label>
                        <input type="checkbox" id="autoScroll" checked> 自动滚动到底部
                    </label>
                </div>

                <div id="logConnectionStatus" class="status info">
                    <strong>连接状态：</strong> <span id="connectionStatusText">未连接</span>
                </div>

                <div id="logContainer"
                    style="background-color: #1e1e1e; color: #ffffff; font-family: 'Courier New', monospace; font-size: 12px; height: 600px; overflow-y: auto; border: 1px solid #333; border-radius: 5px; padding: 15px; white-space: pre-wrap; word-break: break-all;">
                    <div id="logContent">等待连接日志流...</div>
                </div>
            </div>

            <!-- 项目信息标签页 -->
            <div id="aboutTab" class="tab-content">
                <h3>项目信息</h3>
                <p>关于GCLI2API项目的详细信息和支持方式</p>

                <!-- 项目介绍 -->
                <div
                    style="background-color: #f8f9fa; padding: 20px; border-radius: 10px; margin: 20px 0; border-left: 4px solid #007bff;">
                    <h4 style="margin-top: 0; color: #007bff;">📋 项目简介</h4>
                    <p style="margin: 10px 0; line-height: 1.6; color: #495057;">
                        GCLI2API是一个将Google Gemini API转换为OpenAI 和GEMINI API格式的代理工具，支持多账户管理、自动轮换、实时日志监控等功能。
                    </p>
                    <div style="margin: 15px 0;">
                        <p style="margin: 5px 0;"><strong>🔗 项目地址：</strong> <a
                                href="https://github.com/su-kaka/gcli2api" target="_blank"
                                style="color: #007bff; text-decoration: none;">GitHub - su-kaka/gcli2api</a></p>
                        <p style="margin: 5px 0;"><strong>⚠️ 使用声明：</strong> <span
                                style="color: #dc3545; font-weight: 500;">禁止商业用途和倒卖 - 仅供学习使用</span></p>
                    </div>
                </div>

                <!-- 功能特性 -->
                <div
                    style="background-color: #e7f3ff; padding: 20px; border-radius: 10px; margin: 20px 0; border-left: 4px solid #17a2b8;">
                    <h4 style="margin-top: 0; color: #17a2b8;">✨ 主要功能</h4>
                    <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 15px;">
                        <div>
                            <p><strong>🔄 多账户管理：</strong> 支持批量上传和管理多个Google账户</p>
                            <p><strong>⚡ 自动轮换：</strong> 智能轮换账户，避免单账户限额</p>
                            <p><strong>📊 实时监控：</strong> 使用统计、错误监控、实时日志</p>
                        </div>
                        <div>
                            <p><strong>🛡️ 安全可靠：</strong> OAuth2认证、自动封禁异常账户</p>
                            <p><strong>🎛️ 配置灵活：</strong> 支持热更新配置、代理设置</p>
                            <p><strong>📱 界面友好：</strong> 响应式设计、移动端适配</p>
                        </div>
                    </div>
                </div>

                <!-- 支持项目 -->
                <div
                    style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 30px; border-radius: 15px; margin: 30px 0; text-align: center; box-shadow: 0 8px 32px rgba(102, 126, 234, 0.3);">
                    <h4 style="margin: 0 0 15px 0; font-size: 24px; font-weight: 600;">💝 支持项目发展</h4>
                    <p style="margin: 0 0 25px 0; font-size: 16px; opacity: 0.9; line-height: 1.6;">
                        如果这个项目对您有帮助，欢迎通过币安扫码捐赠支持项目的持续发展！<br>
                        您的每一份支持都是我们前进的动力 ❤️
                    </p>

                    <div
                        style="display: inline-block; background: white; padding: 20px; border-radius: 15px; box-shadow: 0 4px 25px rgba(0,0,0,0.1);">
                        <img src="docs/币安.jpg" alt="币安捐赠二维码"
                            style="width: 200px; height: 200px; border-radius: 10px; display: block;">
                        <p style="color: #666; margin: 12px 0 0 0; font-size: 14px; font-weight: 600;">扫码币安捐赠</p>
                    </div>
                </div>

                <!-- 联系和反馈 -->
                <div
                    style="background-color: #d1ecf1; padding: 20px; border-radius: 10px; margin: 20px 0; border-left: 4px solid #bee5eb;">
                    <h4 style="margin-top: 0; color: #0c5460;">📞 联系我们</h4>
                    <div style="color: #0c5460; line-height: 1.6;">
                        <p>• <strong>问题反馈：</strong> 通过GitHub Issues提交问题和建议</p>
                        <p>• <strong>功能请求：</strong> 在GitHub Discussions中讨论新功能</p>
                        <p>• <strong>代码贡献：</strong> 欢迎提交Pull Request改进项目</p>
                        <p>• <strong>文档完善：</strong> 帮助改进项目文档和使用指南</p>
                    </div>
                </div>
            </div>

            <div id="statusSection"></div>

            <!-- 项目信息 -->
            <div
                style="background-color: #f8f9fa; border: 1px solid #dee2e6; border-radius: 8px; padding: 12px; margin-top: 30px; text-align: center; border-left: 4px solid #007bff;">
                <p style="margin: 5px 0; font-size: 14px; color: #495057;">GitHub: <a
                        href="https://github.com/su-kaka/gcli2api" target="_blank"
                        style="color: #007bff; text-decoration: none;">https://github.com/su-kaka/gcli2api</a></p>
                <p style="margin: 5px 0; font-size: 14px; color: #dc3545; font-weight: 500;">⚠️ 禁止商业用途和倒卖 - 仅供学习使用 ⚠️
                </p>
            </div>
        </div>
    </div>

    <!-- 限制设置弹窗 -->
    <div id="limitsModal" class="modal">
        <div class="modal-content">
            <div class="modal-header">
                <h3 class="modal-title">设置使用限制</h3>
                <button class="modal-close" onclick="closeLimitsModal()">&times;</button>
            </div>
            <div class="modal-body">
                <div class="form-group">
                    <label for="modalFilename">文件名:</label>
                    <input type="text" id="modalFilename" class="config-input" readonly />
                </div>
                <div class="form-group">
                    <label for="modalGeminiLimit">Gemini 2.5 Pro 每日限制:</label>
                    <input type="number" id="modalGeminiLimit" class="config-input" min="1" max="10000" />
                    <small class="config-note">每日Gemini 2.5 Pro模型调用次数限制</small>
                </div>
                <div class="form-group">
                    <label for="modalTotalLimit">所有模型每日限制:</label>
                    <input type="number" id="modalTotalLimit" class="config-input" min="1" max="50000" />
                    <small class="config-note">每日所有模型调用次数总限制</small>
                </div>
            </div>
            <div class="modal-footer">
                <button class="btn" onclick="closeLimitsModal()" style="background-color: #6c757d;">取消</button>
                <button class="btn" onclick="saveLimits()">保存</button>
            </div>
        </div>
    </div>

    <script>
        let currentProjectId = '';
        let authInProgress = false;
        let uploadSelectedFiles = []; // 上传页面用的文件列表
        let authToken = '';
        let credsData = {};

        // 分页和筛选相关变量
        let filteredCredsData = {};
        let currentPage = 1;
        let pageSize = 20;
        let currentFilter = 'all';
        let currentErrorCodeFilter = 'all';
        let selectedCredFiles = new Set(); // 选中的凭证文件名集合
        let availableErrorCodes = new Set(); // 所有可用的错误码
        let statsData = {
            total: 0,
            normal: 0,
            disabled: 0
        };

        function showStatus(message, type = 'info') {
            console.log('showStatus called:', message, type);
            const statusSection = document.getElementById('statusSection');
            if (statusSection) {
                statusSection.innerHTML = `<div class="status ${type}">${message}</div>`;
            } else {
                console.error('statusSection not found');
                alert(message); // 临时回退方案
            }
        }

        // 登录相关函数
        async function login() {
            console.log('Login function called');
            const password = document.getElementById('loginPassword').value;
            console.log('Password length:', password ? password.length : 0);

            if (!password) {
                showStatus('请输入密码', 'error');
                return;
            }

            try {
                console.log('Sending login request...');
                const response = await fetch('/auth/login', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify({ password: password })
                });

                console.log('Login response status:', response.status);
                const data = await response.json();
                console.log('Login response data:', data);

                if (response.ok) {
                    authToken = data.token;
                    console.log('Login successful, token received');
                    document.getElementById('loginSection').classList.add('hidden');
                    document.getElementById('mainSection').classList.remove('hidden');
                    showStatus('登录成功', 'success');
                } else {
                    console.log('Login failed:', data);
                    showStatus(`登录失败: ${data.detail || data.error || '未知错误'}`, 'error');
                }
            } catch (error) {
                console.error('Login error:', error);
                showStatus(`网络错误: ${error.message}`, 'error');
            }
        }

        function handlePasswordEnter(event) {
            if (event.key === 'Enter') {
                login();
            }
        }

        // 标签页切换
        function switchTab(tabName) {
            // 移除所有活动标签
            document.querySelectorAll('.tab').forEach(tab => tab.classList.remove('active'));
            document.querySelectorAll('.tab-content').forEach(content => content.classList.remove('active'));

            // 激活选中标签
            event.target.classList.add('active');
            document.getElementById(tabName + 'Tab').classList.add('active');

            // 如果切换到文件管理页面，自动加载数据
            if (tabName === 'manage') {
                refreshCredsStatus();
            }
            // 如果切换到使用统计页面，自动加载统计
            if (tabName === 'usage') {
                refreshUsageStats();
            }
            // 如果切换到配置管理页面，自动加载配置
            if (tabName === 'config') {
                loadConfig();
            }
            // 如果切换到环境变量页面，自动检查状态
            if (tabName === 'envload') {
                checkEnvCredsStatus();
            }
            // 如果切换到日志页面，自动连接WebSocket
            if (tabName === 'logs') {
                connectWebSocket();
            }
        }

        // 获取认证头
        function getAuthHeaders() {
            return {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${authToken}`
            };
        }

        async function startAuth() {
            const projectId = document.getElementById('projectId').value.trim();
            const getAllProjects = document.getElementById('getAllProjectsCreds').checked;
            // 项目ID现在是可选的
            currentProjectId = projectId || null;

            const btn = document.getElementById('getAuthBtn');
            btn.disabled = true;
            btn.textContent = '正在获取认证链接...';

            try {
                const requestBody = {};
                if (projectId) {
                    requestBody.project_id = projectId;
                }
                if (getAllProjects) {
                    requestBody.get_all_projects = true;
                    showStatus('批量并发认证模式：将为当前账号所有项目生成认证链接...', 'info');
                } else if (projectId) {
                    showStatus('使用指定的项目ID生成认证链接...', 'info');
                } else {
                    showStatus('将尝试自动检测项目ID，正在生成认证链接...', 'info');
                }

                const response = await fetch('/auth/start', {
                    method: 'POST',
                    headers: getAuthHeaders(),
                    body: JSON.stringify(requestBody)
                });

                const data = await response.json();

                if (response.ok) {
                    document.getElementById('authUrl').href = data.auth_url;
                    document.getElementById('authUrl').textContent = data.auth_url;
                    document.getElementById('authUrlSection').classList.remove('hidden');

                    if (getAllProjects) {
                        showStatus('批量并发认证链接已生成，完成授权后将并发为所有可访问项目生成凭证文件', 'info');
                    } else if (data.auto_project_detection) {
                        showStatus('认证链接已生成（将在认证完成后自动检测项目ID），请点击链接完成授权', 'info');
                    } else {
                        showStatus(`认证链接已生成（项目ID: ${data.detected_project_id}），请点击链接完成授权`, 'info');
                    }
                    authInProgress = true;
                } else {
                    showStatus(`错误: ${data.error || '获取认证链接失败'}`, 'error');
                }
            } catch (error) {
                showStatus(`网络错误: ${error.message}`, 'error');
            } finally {
                btn.disabled = false;
                btn.textContent = '获取认证链接';
            }
        }

        async function getCredentials() {
            if (!authInProgress) {
                showStatus('请先获取认证链接并完成授权', 'error');
                return;
            }

            const btn = document.getElementById('getCredsBtn');
            const getAllProjects = document.getElementById('getAllProjectsCreds').checked;
            btn.disabled = true;
            btn.textContent = getAllProjects ? '并发批量获取所有项目凭证中...' : '等待OAuth回调中...';

            try {
                if (getAllProjects) {
                    showStatus('正在并发为所有项目获取认证凭证，采用并发处理提升速度...', 'info');
                } else {
                    showStatus('正在等待OAuth回调，这可能需要一些时间...', 'info');
                }

                const requestBody = {};
                if (currentProjectId) {
                    requestBody.project_id = currentProjectId;
                }
                if (getAllProjects) {
                    requestBody.get_all_projects = true;
                }

                const response = await fetch('/auth/callback', {
                    method: 'POST',
                    headers: getAuthHeaders(),
                    body: JSON.stringify(requestBody)
                });

                const data = await response.json();

                if (response.ok) {
                    const credentialsSection = document.getElementById('credentialsSection');
                    const credentialsContent = document.getElementById('credentialsContent');

                    if (getAllProjects && data.multiple_credentials) {
                        // 处理多项目认证结果
                        const results = data.multiple_credentials;
                        let resultText = `批量并发认证完成！成功为 ${results.success.length} 个项目生成凭证：\n\n`;

                        // 显示成功的项目
                        results.success.forEach((item, index) => {
                            resultText += `${index + 1}. 项目: ${item.project_name} (${item.project_id})\n`;
                            resultText += `   文件: ${item.file_path}\n\n`;
                        });

                        // 显示失败的项目（如果有）
                        if (results.failed.length > 0) {
                            resultText += `\n失败的项目 (${results.failed.length} 个):\n`;
                            results.failed.forEach((item, index) => {
                                resultText += `${index + 1}. 项目: ${item.project_name} (${item.project_id})\n`;
                                resultText += `   错误: ${item.error}\n\n`;
                            });
                        }

                        credentialsContent.textContent = resultText;
                        showStatus(`✅ 批量并发认证完成！成功生成 ${results.success.length} 个项目的凭证文件${results.failed.length > 0 ? `，${results.failed.length} 个项目失败` : ''}`, 'success');
                    } else {
                        // 处理单项目认证结果
                        credentialsContent.textContent = JSON.stringify(data.credentials, null, 2);

                        if (data.auto_detected_project) {
                            showStatus(`✅ 认证成功！项目ID已自动检测为: ${data.credentials.project_id}，文件已保存到: ${data.file_path}`, 'success');
                        } else {
                            showStatus(`✅ 认证成功！文件已保存到: ${data.file_path}`, 'success');
                        }
                    }

                    credentialsSection.classList.remove('hidden');
                    authInProgress = false;
                } else {
                    // 检查是否需要项目选择
                    if (data.requires_project_selection && data.available_projects) {
                        let projectOptions = "请选择一个项目：\n\n";
                        data.available_projects.forEach((project, index) => {
                            projectOptions += `${index + 1}. ${project.name} (${project.projectId})\n`;
                        });
                        projectOptions += `\n请输入序号 (1-${data.available_projects.length}):`;

                        const selection = prompt(projectOptions);
                        const projectIndex = parseInt(selection) - 1;

                        if (projectIndex >= 0 && projectIndex < data.available_projects.length) {
                            const selectedProject = data.available_projects[projectIndex];
                            currentProjectId = selectedProject.projectId;
                            btn.textContent = '重新尝试获取认证文件';
                            showStatus(`使用选择的项目 ${selectedProject.name} (${selectedProject.projectId}) 重新尝试...`, 'info');
                            setTimeout(() => getCredentials(), 1000);
                            return;
                        } else {
                            showStatus('无效的选择，请重新开始认证', 'error');
                        }
                    }
                    // 检查是否需要手动输入项目ID
                    else if (data.requires_manual_project_id) {
                        const userProjectId = prompt('无法自动检测项目ID，请手动输入您的Google Cloud项目ID:');
                        if (userProjectId && userProjectId.trim()) {
                            // 重新尝试，使用用户输入的项目ID
                            currentProjectId = userProjectId.trim();
                            btn.textContent = '重新尝试获取认证文件';
                            showStatus('使用手动输入的项目ID重新尝试...', 'info');
                            setTimeout(() => getCredentials(), 1000);
                            return;
                        } else {
                            showStatus('需要项目ID才能完成认证，请重新开始并输入正确的项目ID', 'error');
                        }
                    } else {
                        showStatus(`❌ 错误: ${data.error || '获取认证文件失败'}`, 'error');
                        if (data.error && data.error.includes('未接收到授权回调')) {
                            showStatus('提示：请确保已完成浏览器中的OAuth认证，并看到了"OAuth authentication successful"页面', 'info');
                        }
                    }
                }
            } catch (error) {
                showStatus(`网络错误: ${error.message}`, 'error');
            } finally {
                btn.disabled = false;
                btn.textContent = '获取认证文件';
            }
        }

        // 文件上传相关函数
        function handleFileSelect(event) {
            const files = Array.from(event.target.files);
            addFiles(files);
        }

        function addFiles(files) {
            files.forEach(file => {
                if (file.type === 'application/json' || file.name.endsWith('.json') ||
                    file.type === 'application/zip' || file.name.endsWith('.zip')) {
                    if (!uploadSelectedFiles.find(f => f.name === file.name && f.size === file.size)) {
                        uploadSelectedFiles.push(file);
                    }
                } else {
                    showStatus(`文件 ${file.name} 格式不支持，只支持JSON和ZIP文件`, 'error');
                }
            });

            updateFileList();
        }

        function updateFileList() {
            const fileList = document.getElementById('fileList');
            const fileListSection = document.getElementById('fileListSection');

            if (uploadSelectedFiles.length === 0) {
                fileListSection.classList.add('hidden');
                return;
            }

            fileListSection.classList.remove('hidden');
            fileList.innerHTML = '';

            uploadSelectedFiles.forEach((file, index) => {
                const fileItem = document.createElement('div');
                fileItem.className = 'file-item';
                const isZip = file.name.endsWith('.zip');
                const fileIcon = isZip ? '📦' : '📄';
                const fileType = isZip ? ' (ZIP压缩包)' : ' (JSON文件)';
                fileItem.innerHTML = `
                    <div>
                        <span class="file-name">${fileIcon} ${file.name}</span>
                        <span class="file-size">(${formatFileSize(file.size)}${fileType})</span>
                    </div>
                    <button class="remove-btn" onclick="removeFile(${index})">删除</button>
                `;
                fileList.appendChild(fileItem);
            });
        }

        function removeFile(index) {
            uploadSelectedFiles.splice(index, 1);
            updateFileList();
        }

        function clearFiles() {
            uploadSelectedFiles = [];
            updateFileList();
        }

        function formatFileSize(bytes) {
            if (bytes < 1024) return bytes + ' B';
            if (bytes < 1024 * 1024) return Math.round(bytes / 1024) + ' KB';
            return Math.round(bytes / (1024 * 1024)) + ' MB';
        }

        async function uploadFiles() {
            if (uploadSelectedFiles.length === 0) {
                showStatus('请选择要上传的文件', 'error');
                return;
            }

            // 检查文件大小
            const totalSize = uploadSelectedFiles.reduce((sum, file) => sum + file.size, 0);
            const maxSize = 200 * 1024 * 1024; // 200MB limit
            if (totalSize > maxSize) {
                showStatus(`文件总大小 ${(totalSize / 1024 / 1024).toFixed(1)}MB 超过限制 ${maxSize / 1024 / 1024}MB。请分批上传或删除部分文件。`, 'error');
                return;
            }

            // 检查单个文件大小
            for (const file of uploadSelectedFiles) {
                if (file.size > 5 * 1024 * 1024) {
                    showStatus(`文件 "${file.name}" 大小 ${(file.size / 1024 / 1024).toFixed(1)}MB 超过单文件5MB限制`, 'error');
                    return;
                }
            }

            const progressSection = document.getElementById('uploadProgressSection');
            const progressFill = document.getElementById('progressFill');
            const progressText = document.getElementById('progressText');

            progressSection.classList.remove('hidden');

            const formData = new FormData();
            uploadSelectedFiles.forEach(file => {
                formData.append('files', file);
            });

            // 检查是否有ZIP文件，给用户提示
            const hasZipFiles = uploadSelectedFiles.some(file => file.name.endsWith('.zip'));
            if (hasZipFiles) {
                showStatus('正在上传并解压ZIP文件...', 'info');
            }

            try {
                const xhr = new XMLHttpRequest();

                // 设置超时时间 (5分钟)
                xhr.timeout = 300000;

                xhr.upload.onprogress = function (event) {
                    if (event.lengthComputable) {
                        const percentComplete = (event.loaded / event.total) * 100;
                        progressFill.style.width = percentComplete + '%';
                        progressText.textContent = Math.round(percentComplete) + '%';
                    }
                };

                xhr.onload = function () {
                    if (xhr.status === 200) {
                        try {
                            const data = JSON.parse(xhr.responseText);
                            showStatus(`成功上传 ${data.uploaded_count} 个文件`, 'success');
                            clearFiles();
                            progressSection.classList.add('hidden');
                        } catch (e) {
                            showStatus('上传失败: 服务器响应格式错误', 'error');
                        }
                    } else {
                        try {
                            const error = JSON.parse(xhr.responseText);
                            showStatus(`上传失败: ${error.detail || error.error || '未知错误'}`, 'error');
                        } catch (e) {
                            showStatus(`上传失败: HTTP ${xhr.status} - ${xhr.statusText || '未知错误'}`, 'error');
                        }
                    }
                };

                xhr.onerror = function () {
                    console.error('Upload XHR error:', {
                        readyState: xhr.readyState,
                        status: xhr.status,
                        statusText: xhr.statusText,
                        responseText: xhr.responseText,
                        fileCount: uploadSelectedFiles.length,
                        totalSize: (totalSize / 1024 / 1024).toFixed(1) + 'MB'
                    });
                    showStatus(`上传失败：连接中断 - 可能原因：文件过多(${uploadSelectedFiles.length}个)或网络不稳定。建议分批上传。`, 'error');
                    progressSection.classList.add('hidden');
                };

                xhr.ontimeout = function () {
                    showStatus('上传失败：请求超时 - 文件处理时间过长，请减少文件数量或检查网络连接', 'error');
                    progressSection.classList.add('hidden');
                };

                xhr.open('POST', '/auth/upload');
                xhr.setRequestHeader('Authorization', `Bearer ${authToken}`);
                xhr.send(formData);

            } catch (error) {
                showStatus(`上传失败: ${error.message}`, 'error');
            }
        }

        // 拖拽功能
        const uploadArea = document.getElementById('uploadArea');

        uploadArea.addEventListener('dragover', function (event) {
            event.preventDefault();
            uploadArea.classList.add('dragover');
        });

        uploadArea.addEventListener('dragleave', function (event) {
            event.preventDefault();
            uploadArea.classList.remove('dragover');
        });

        uploadArea.addEventListener('drop', function (event) {
            event.preventDefault();
            uploadArea.classList.remove('dragover');

            const files = Array.from(event.dataTransfer.files);
            addFiles(files);
        });

        // WebSocket日志相关变量和函数
        let logWebSocket = null;
        let allLogs = [];
        let filteredLogs = [];
        let currentLogFilter = 'all';

        function connectWebSocket() {
            if (logWebSocket && logWebSocket.readyState === WebSocket.OPEN) {
                showStatus('WebSocket已经连接', 'info');
                return;
            }

            try {
                const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
                const wsUrl = `${protocol}//${window.location.host}/auth/logs/stream`;

                document.getElementById('connectionStatusText').textContent = '连接中...';
                document.getElementById('logConnectionStatus').className = 'status info';

                logWebSocket = new WebSocket(wsUrl);

                logWebSocket.onopen = function (event) {
                    document.getElementById('connectionStatusText').textContent = '已连接';
                    document.getElementById('logConnectionStatus').className = 'status success';
                    showStatus('日志流连接成功', 'success');
                    clearLogsDisplay(); // 只清空前端显示的旧日志，不清空服务器文件
                };

                logWebSocket.onmessage = function (event) {
                    const logLine = event.data;
                    if (logLine.trim()) {
                        allLogs.push(logLine);

                        // 限制日志数量，保留最后1000条
                        if (allLogs.length > 1000) {
                            allLogs = allLogs.slice(-1000);
                        }

                        filterLogs();

                        // 自动滚动到底部
                        if (document.getElementById('autoScroll').checked) {
                            const logContainer = document.getElementById('logContainer');
                            logContainer.scrollTop = logContainer.scrollHeight;
                        }
                    }
                };

                logWebSocket.onclose = function (event) {
                    document.getElementById('connectionStatusText').textContent = '连接断开';
                    document.getElementById('logConnectionStatus').className = 'status error';
                    showStatus('日志流连接断开', 'info');
                };

                logWebSocket.onerror = function (error) {
                    document.getElementById('connectionStatusText').textContent = '连接错误';
                    document.getElementById('logConnectionStatus').className = 'status error';
                    showStatus('日志流连接错误: ' + error, 'error');
                };

            } catch (error) {
                showStatus('创建WebSocket连接失败: ' + error.message, 'error');
                document.getElementById('connectionStatusText').textContent = '连接失败';
                document.getElementById('logConnectionStatus').className = 'status error';
            }
        }

        function disconnectWebSocket() {
            if (logWebSocket) {
                logWebSocket.close();
                logWebSocket = null;
                document.getElementById('connectionStatusText').textContent = '未连接';
                document.getElementById('logConnectionStatus').className = 'status info';
                showStatus('日志流连接已断开', 'info');
            }
        }

        function clearLogsDisplay() {
            // 只清空前端显示的日志，不清空服务器文件
            allLogs = [];
            filteredLogs = [];
            document.getElementById('logContent').textContent = '日志已清空，等待新日志...';
        }

        async function downloadLogs() {
            try {
                // 调用后端API下载日志文件
                const response = await fetch('/auth/logs/download', {
                    method: 'GET',
                    headers: getAuthHeaders()
                });

                if (response.ok) {
                    // 获取文件名
                    const contentDisposition = response.headers.get('Content-Disposition');
                    let filename = 'gcli2api_logs.txt';
                    if (contentDisposition) {
                        const filenameMatch = contentDisposition.match(/filename=(.+)/);
                        if (filenameMatch) {
                            filename = filenameMatch[1];
                        }
                    }

                    // 下载文件
                    const blob = await response.blob();
                    const url = window.URL.createObjectURL(blob);
                    const a = document.createElement('a');
                    a.href = url;
                    a.download = filename;
                    document.body.appendChild(a);
                    a.click();
                    document.body.removeChild(a);
                    window.URL.revokeObjectURL(url);

                    showStatus(`日志文件下载成功: ${filename}`, 'success');
                } else {
                    const errorText = await response.text();
                    let errorMsg = '下载失败';
                    try {
                        const errorData = JSON.parse(errorText);
                        errorMsg = errorData.detail || errorData.error || '未知错误';
                    } catch (e) {
                        errorMsg = errorText || '未知错误';
                    }
                    showStatus(`下载日志失败: ${errorMsg}`, 'error');
                }
            } catch (error) {
                console.error('downloadLogs error:', error);
                showStatus(`下载日志时网络错误: ${error.message}`, 'error');
            }
        }

        async function clearLogs() {
            try {
                // 调用后端API清空日志文件
                const response = await fetch('/auth/logs/clear', {
                    method: 'POST',
                    headers: getAuthHeaders()
                });

                const data = await response.json();

                if (response.ok) {
                    // 清空前端显示的日志
                    clearLogsDisplay();
                    showStatus(data.message, 'success');
                } else {
                    showStatus(`清空日志失败: ${data.detail || data.error || '未知错误'}`, 'error');
                }
            } catch (error) {
                console.error('clearLogs error:', error);
                // 即使后端清空失败，也清空前端显示
                clearLogsDisplay();
                showStatus(`清空日志时网络错误: ${error.message}`, 'error');
            }
        }

        function filterLogs() {
            const filter = document.getElementById('logLevelFilter').value;
            currentLogFilter = filter;

            if (filter === 'all') {
                filteredLogs = [...allLogs];
            } else {
                filteredLogs = allLogs.filter(log => log.toUpperCase().includes(filter));
            }

            displayLogs();
        }

        function displayLogs() {
            const logContent = document.getElementById('logContent');
            if (filteredLogs.length === 0) {
                logContent.textContent = currentLogFilter === 'all' ?
                    '暂无日志...' : `暂无${currentLogFilter}级别的日志...`;
            } else {
                logContent.textContent = filteredLogs.join('\n');
            }
        }

        // 凭证文件管理相关函数
        async function refreshCredsStatus() {
            const credsLoading = document.getElementById('credsLoading');
            const credsList = document.getElementById('credsList');

            try {
                credsLoading.style.display = 'block';
                credsList.innerHTML = '';

                console.log('Fetching creds status...');

                const response = await fetch('/creds/status', {
                    method: 'GET',
                    headers: getAuthHeaders()
                });

                console.log('Creds status response:', response.status);

                const data = await response.json();
                console.log('Creds status data:', data);

                if (response.ok) {
                    credsData = data.creds;

                    // 计算统计数据
                    calculateStats();

                    // 更新统计显示
                    updateStatsDisplay();

                    // 应用筛选并显示第一页
                    currentPage = 1;
                    applyFilters();

                    showStatus(`已加载 ${Object.keys(credsData).length} 个凭证文件`, 'success');
                } else {
                    showStatus(`加载失败: ${data.detail || data.error || '未知错误'}`, 'error');
                }
            } catch (error) {
                console.error('refreshCredsStatus error:', error);
                showStatus(`网络错误: ${error.message}`, 'error');
            } finally {
                credsLoading.style.display = 'none';
            }
        }

        // 计算统计数据
        function calculateStats() {
            statsData = {
                total: 0,
                normal: 0,
                disabled: 0
            };

            // 清空并重新收集错误码
            availableErrorCodes.clear();

            for (const [fullPath, credInfo] of Object.entries(credsData)) {
                statsData.total++;

                if (credInfo.status.disabled) {
                    statsData.disabled++;
                } else {
                    statsData.normal++;
                }

                // 收集错误码信息
                if (credInfo.status.error_codes && credInfo.status.error_codes.length > 0) {
                    credInfo.status.error_codes.forEach(code => {
                        availableErrorCodes.add(code);
                    });
                }
            }

            // 更新错误码快速筛选按钮
            updateErrorCodeBadges();
        }

        // 更新错误码筛选快速按钮
        function updateErrorCodeBadges() {
            const errorCodeBadges = document.getElementById('errorCodeBadges');
            errorCodeBadges.innerHTML = '';

            if (availableErrorCodes.size === 0) {
                errorCodeBadges.innerHTML = '<span style="color: #28a745;">所有文件都无错误</span>';
                return;
            }

            const sortedCodes = Array.from(availableErrorCodes).sort((a, b) => a - b);
            sortedCodes.forEach(code => {
                const badge = document.createElement('span');
                badge.className = 'error-code-badge';
                badge.textContent = code;
                badge.onclick = () => filterByErrorCode(code);
                errorCodeBadges.appendChild(badge);
            });
        }

        // 按错误码快速筛选
        function filterByErrorCode(code) {
            document.getElementById('errorCodeFilter').value = code.toString();
            applyFilters();
        }

        // 更新统计显示
        function updateStatsDisplay() {
            document.getElementById('statTotal').textContent = statsData.total;
            document.getElementById('statNormal').textContent = statsData.normal;
            document.getElementById('statDisabled').textContent = statsData.disabled;
        }

        // 应用筛选
        function applyFilters() {
            const statusFilter = document.getElementById('statusFilter').value;
            const errorCodeFilter = document.getElementById('errorCodeFilter').value;
            currentFilter = statusFilter;
            currentErrorCodeFilter = errorCodeFilter;
            filteredCredsData = {};

            for (const [fullPath, credInfo] of Object.entries(credsData)) {
                let shouldInclude = false;

                // 状态筛选
                switch (statusFilter) {
                    case 'all':
                        shouldInclude = true;
                        break;
                    case 'normal':
                        shouldInclude = !credInfo.status.disabled;
                        break;
                    case 'disabled':
                        shouldInclude = credInfo.status.disabled;
                        break;
                }

                // 如果状态筛选已经排除，跳过错误码筛选
                if (!shouldInclude) {
                    continue;
                }

                // 错误码筛选
                const errorCodes = credInfo.status.error_codes || [];
                switch (errorCodeFilter) {
                    case 'all':
                        // 保持当前状态
                        break;
                    case 'no-errors':
                        shouldInclude = errorCodes.length === 0;
                        break;
                    case 'has-errors':
                        shouldInclude = errorCodes.length > 0;
                        break;
                    default:
                        // 具体错误码筛选
                        const targetCode = parseInt(errorCodeFilter);
                        if (!isNaN(targetCode)) {
                            shouldInclude = errorCodes.includes(targetCode);
                        }
                        break;
                }

                if (shouldInclude) {
                    filteredCredsData[fullPath] = credInfo;
                }
            }

            // 清空选择状态
            selectedCredFiles.clear();
            updateBatchControls();

            currentPage = 1;
            renderCredsList();
            updatePagination();
        }

        // 获取当前页数据
        function getCurrentPageData() {
            const filteredEntries = Object.entries(filteredCredsData);
            const startIndex = (currentPage - 1) * pageSize;
            const endIndex = startIndex + pageSize;
            return filteredEntries.slice(startIndex, endIndex);
        }

        // 获取总页数
        function getTotalPages() {
            return Math.ceil(Object.keys(filteredCredsData).length / pageSize);
        }

        // 渲染凭证列表
        function renderCredsList() {
            const credsList = document.getElementById('credsList');
            credsList.innerHTML = '';

            const currentPageData = getCurrentPageData();

            if (currentPageData.length === 0) {
                const message = Object.keys(credsData).length === 0 ?
                    '暂无凭证文件' : '当前筛选条件下暂无数据';
                credsList.innerHTML = `<p style="text-align: center; color: #666;">${message}</p>`;
                document.getElementById('paginationContainer').style.display = 'none';
                return;
            }

            for (const [fullPath, credInfo] of currentPageData) {
                const card = createCredCard(fullPath, credInfo);
                credsList.appendChild(card);
            }

            document.getElementById('paginationContainer').style.display = getTotalPages() > 1 ? 'flex' : 'none';

            // 更新批量控件状态
            updateBatchControls();
        }

        // 更新分页信息
        function updatePagination() {
            const totalPages = getTotalPages();
            const totalItems = Object.keys(filteredCredsData).length;
            const startItem = (currentPage - 1) * pageSize + 1;
            const endItem = Math.min(currentPage * pageSize, totalItems);

            document.getElementById('paginationInfo').textContent =
                `第 ${currentPage} 页，共 ${totalPages} 页 (显示 ${startItem}-${endItem}，共 ${totalItems} 项)`;

            document.getElementById('prevPageBtn').disabled = currentPage <= 1;
            document.getElementById('nextPageBtn').disabled = currentPage >= totalPages;
        }

        // 切换页面
        function changePage(direction) {
            const totalPages = getTotalPages();
            const newPage = currentPage + direction;

            if (newPage >= 1 && newPage <= totalPages) {
                currentPage = newPage;
                renderCredsList();
                updatePagination();
            }
        }

        // 改变每页显示数量
        function changePageSize() {
            pageSize = parseInt(document.getElementById('pageSizeSelect').value);
            currentPage = 1;
            renderCredsList();
            updatePagination();
        }

        function createCredCard(fullPath, credInfo) {
            const div = document.createElement('div');
            const status = credInfo.status;
            const filename = credInfo.filename;

            // 调试：记录状态
            if (filename.includes('atomic-affinity')) {
                console.log(`Creating card for ${filename}:`, status);
            }

            // 设置卡片状态样式
            let cardClass = 'cred-card';
            if (status.disabled) cardClass += ' disabled';

            div.className = cardClass;

            // 创建状态标签
            let statusBadges = '';
            if (status.disabled) {
                statusBadges += '<span class="status-badge disabled">已禁用</span>';
            } else {
                statusBadges += '<span class="status-badge enabled">已启用</span>';
            }


            // 调试：记录 error_codes
            console.log(`Error codes for ${filename}:`, status.error_codes);

            if (status.error_codes && status.error_codes.length > 0) {
                statusBadges += `<span class="error-codes">错误码: ${status.error_codes.join(', ')}</span>`;
                // 检查是否包含自动封禁的错误码
                const autoBanErrors = status.error_codes.filter(code => code === 400 || code === 403);
                if (autoBanErrors.length > 0 && status.disabled) {
                    statusBadges += `<span class="status-badge" style="background-color: #e74c3c; color: white;">AUTO_BAN</span>`;
                }
            } else {
                // 显示无错误码状态
                statusBadges += `<span class="status-badge" style="background-color: #28a745; color: white;">无错误</span>`;
            }

            // 为HTML ID生成安全的标识符
            const pathId = btoa(encodeURIComponent(fullPath)).replace(/[+/=]/g, '_');

            // 创建操作按钮 - 使用文件名而不是完整路径
            let actionButtons = '';
            if (status.disabled) {
                actionButtons += `<button class="cred-btn enable" data-filename="${filename}" data-action="enable">启用</button>`;
            } else {
                actionButtons += `<button class="cred-btn disable" data-filename="${filename}" data-action="disable">禁用</button>`;
            }

            actionButtons += `
                <button class="cred-btn view" onclick="toggleCredDetails('${pathId}')">查看内容</button>
                <button class="cred-btn download" onclick="downloadCred('${filename}')">下载</button>
                <button class="cred-btn email" onclick="fetchUserEmail('${filename}')">查看账号邮箱</button>
                <button class="cred-btn delete" data-filename="${filename}" data-action="delete">删除</button>
            `;

            // 构建邮箱显示
            let emailInfo = '';
            if (credInfo.user_email) {
                emailInfo = `<div class="cred-email" style="font-size: 12px; color: #666; margin-top: 2px;">${credInfo.user_email}</div>`;
            } else {
                emailInfo = `<div class="cred-email" style="font-size: 12px; color: #999; margin-top: 2px; font-style: italic;">未获取邮箱</div>`;
            }

            div.innerHTML = `
                <div class="cred-header">
                    <div style="display: flex; align-items: center; gap: 10px;">
                        <input type="checkbox" class="file-checkbox" data-filename="${filename}" onchange="toggleFileSelection('${filename}')">
                        <div>
                            <div class="cred-filename">${filename}</div>
                            ${emailInfo}
                        </div>
                    </div>
                    <div class="cred-status">${statusBadges}</div>
                </div>
                <div class="cred-actions">${actionButtons}</div>
                <div class="cred-details" id="details-${pathId}">
                    <div class="cred-content"></div>
                </div>
            `;

            // 设置文件内容（避免HTML注入）
            const contentDiv = div.querySelector('.cred-content');
            if (credInfo.content) {
                contentDiv.textContent = JSON.stringify(credInfo.content, null, 2);
            } else {
                contentDiv.textContent = credInfo.error || '无法读取文件内容';
            }

            // 添加事件监听器到按钮
            const actionButtonElements = div.querySelectorAll('[data-filename][data-action]');
            actionButtonElements.forEach(button => {
                button.addEventListener('click', function () {
                    const filename = this.getAttribute('data-filename');
                    const action = this.getAttribute('data-action');

                    if (action === 'delete') {
                        deleteCred(filename);
                    } else {
                        credAction(filename, action);
                    }
                });
            });

            return div;
        }

        async function credAction(filename, action) {
            try {
                console.log('Performing action:', action, 'on file:', filename);
                console.log('Filename type:', typeof filename);
                console.log('Filename length:', filename.length);
                console.log('Ends with .json:', filename.endsWith('.json'));

                const requestBody = {
                    filename: filename,
                    action: action
                };

                console.log('Request body:', requestBody);

                const response = await fetch('/creds/action', {
                    method: 'POST',
                    headers: getAuthHeaders(),
                    body: JSON.stringify(requestBody)
                });

                console.log('Response status:', response.status);

                const data = await response.json();
                console.log('Response data:', data);

                if (response.ok) {
                    showStatus(data.message, 'success');
                    await refreshCredsStatus(); // 刷新状态
                } else {
                    showStatus(`操作失败: ${data.detail || data.error || '未知错误'}`, 'error');
                }
            } catch (error) {
                console.error('credAction error:', error);
                showStatus(`网络错误: ${error.message}`, 'error');
            }
        }

        function toggleCredDetails(pathId) {
            const detailsId = 'details-' + pathId;
            const details = document.getElementById(detailsId);
            if (details) {
                details.classList.toggle('show');
            }
        }

        async function downloadCred(filename) {
            try {
                const response = await fetch(`/creds/download/${filename}`, {
                    method: 'GET',
                    headers: {
                        'Authorization': `Bearer ${authToken}`
                    }
                });

                if (response.ok) {
                    const blob = await response.blob();
                    const url = window.URL.createObjectURL(blob);
                    const a = document.createElement('a');
                    a.style.display = 'none';
                    a.href = url;
                    a.download = filename;
                    document.body.appendChild(a);
                    a.click();
                    window.URL.revokeObjectURL(url);
                    document.body.removeChild(a);
                    showStatus(`已下载文件: ${filename}`, 'success');
                } else {
                    const data = await response.json();
                    showStatus(`下载失败: ${data.error}`, 'error');
                }
            } catch (error) {
                showStatus(`下载失败: ${error.message}`, 'error');
            }
        }

        async function downloadAllCreds() {
            try {
                const response = await fetch('/creds/download-all', {
                    method: 'GET',
                    headers: {
                        'Authorization': `Bearer ${authToken}`
                    }
                });

                if (response.ok) {
                    const blob = await response.blob();
                    const url = window.URL.createObjectURL(blob);
                    const a = document.createElement('a');
                    a.style.display = 'none';
                    a.href = url;
                    a.download = 'credentials.zip';
                    document.body.appendChild(a);
                    a.click();
                    window.URL.revokeObjectURL(url);
                    document.body.removeChild(a);
                    showStatus('已下载所有凭证文件', 'success');
                } else {
                    const data = await response.json();
                    showStatus(`打包下载失败: ${data.error}`, 'error');
                }
            } catch (error) {
                showStatus(`打包下载失败: ${error.message}`, 'error');
            }
        }

        async function deleteCred(filename) {
            if (!confirm(`确定要删除凭证文件吗？\n${filename}`)) {
                return;
            }

            await credAction(filename, 'delete');
        }

        // 配置管理相关函数
        let currentConfig = {};
        let envLockedFields = new Set();

        async function loadConfig() {
            const configLoading = document.getElementById('configLoading');
            const configForm = document.getElementById('configForm');

            try {
                configLoading.style.display = 'block';
                configForm.classList.add('hidden');

                const response = await fetch('/config/get', {
                    method: 'GET',
                    headers: getAuthHeaders()
                });

                const data = await response.json();

                if (response.ok) {
                    currentConfig = data.config;
                    envLockedFields = new Set(data.env_locked || []);

                    populateConfigForm();
                    configForm.classList.remove('hidden');
                    showStatus('配置加载成功', 'success');
                } else {
                    showStatus(`加载配置失败: ${data.detail || data.error || '未知错误'}`, 'error');
                }
            } catch (error) {
                console.error('loadConfig error:', error);
                showStatus(`网络错误: ${error.message}`, 'error');
            } finally {
                configLoading.style.display = 'none';
            }
        }

        function populateConfigForm() {
            // 服务器配置
            setConfigField('host', currentConfig.host || '0.0.0.0');
            setConfigField('port', currentConfig.port || 7861);
            setConfigField('configApiPassword', currentConfig.api_password || '');
            setConfigField('configPanelPassword', currentConfig.panel_password || '');
            setConfigField('configPassword', currentConfig.password || 'pwd');

            // 基础配置
            setConfigField('credentialsDir', currentConfig.credentials_dir || '');
            setConfigField('proxy', currentConfig.proxy || '');

            // 端点配置
            setConfigField('codeAssistEndpoint', currentConfig.code_assist_endpoint || '');
            setConfigField('oauthProxyUrl', currentConfig.oauth_proxy_url || '');
            setConfigField('googleapisProxyUrl', currentConfig.googleapis_proxy_url || '');
            setConfigField('resourceManagerApiUrl', currentConfig.resource_manager_api_url || '');
            setConfigField('serviceUsageApiUrl', currentConfig.service_usage_api_url || '');

            // 自动封禁配置
            document.getElementById('autoBanEnabled').checked = Boolean(currentConfig.auto_ban_enabled);
            setConfigField('autoBanErrorCodes', (currentConfig.auto_ban_error_codes || []).join(','));

            // 性能配置
            setConfigField('callsPerRotation', currentConfig.calls_per_rotation || 10);

            // 429重试配置
            document.getElementById('retry429Enabled').checked = Boolean(currentConfig.retry_429_enabled);
            setConfigField('retry429MaxRetries', currentConfig.retry_429_max_retries || 20);
            setConfigField('retry429Interval', currentConfig.retry_429_interval || 0.1);

            // 兼容性配置
            document.getElementById('compatibilityModeEnabled').checked = Boolean(currentConfig.compatibility_mode_enabled);

            // 抗截断配置
            setConfigField('antiTruncationMaxAttempts', currentConfig.anti_truncation_max_attempts || 3);
        }

        function setConfigField(fieldId, value) {
            const field = document.getElementById(fieldId);
            if (field) {
                field.value = value;

                // 检查是否被环境变量锚定
                const configKey = fieldId.replace(/([A-Z])/g, '_$1').toLowerCase();
                if (envLockedFields.has(configKey)) {
                    field.disabled = true;
                    field.classList.add('env-locked');
                } else {
                    field.disabled = false;
                    field.classList.remove('env-locked');
                }
            }
        }

        async function saveConfig() {
            try {
                // 调试：检查password字段的实际值
                const passwordElement = document.getElementById('configPassword');
                console.log('DEBUG: configPassword元素:', passwordElement);
                console.log('DEBUG: configPassword值:', passwordElement ? passwordElement.value : 'ELEMENT_NOT_FOUND');

                const config = {
                    host: document.getElementById('host').value.trim(),
                    port: parseInt(document.getElementById('port').value) || 7861,
                    api_password: document.getElementById('configApiPassword').value.trim(),
                    panel_password: document.getElementById('configPanelPassword').value.trim(),
                    password: document.getElementById('configPassword').value.trim(),
                    code_assist_endpoint: document.getElementById('codeAssistEndpoint').value.trim(),
                    credentials_dir: document.getElementById('credentialsDir').value.trim(),
                    proxy: document.getElementById('proxy').value.trim(),
                    // 端点配置
                    oauth_proxy_url: document.getElementById('oauthProxyUrl').value.trim(),
                    googleapis_proxy_url: document.getElementById('googleapisProxyUrl').value.trim(),
                    resource_manager_api_url: document.getElementById('resourceManagerApiUrl').value.trim(),
                    service_usage_api_url: document.getElementById('serviceUsageApiUrl').value.trim(),
                    auto_ban_enabled: document.getElementById('autoBanEnabled').checked,
                    auto_ban_error_codes: document.getElementById('autoBanErrorCodes').value
                        .split(',')
                        .map(code => parseInt(code.trim()))
                        .filter(code => !isNaN(code)),
                    calls_per_rotation: parseInt(document.getElementById('callsPerRotation').value) || 10,
                    retry_429_enabled: document.getElementById('retry429Enabled').checked,
                    retry_429_max_retries: parseInt(document.getElementById('retry429MaxRetries').value) || 20,
                    retry_429_interval: parseFloat(document.getElementById('retry429Interval').value) || 0.1,
                    // 兼容性配置
                    compatibility_mode_enabled: document.getElementById('compatibilityModeEnabled').checked,
                    // 抗截断配置
                    anti_truncation_max_attempts: parseInt(document.getElementById('antiTruncationMaxAttempts').value) || 3
                };

                const response = await fetch('/config/save', {
                    method: 'POST',
                    headers: getAuthHeaders(),
                    body: JSON.stringify({ config: config })
                });

                const data = await response.json();

                if (response.ok) {
                    let message = '配置保存成功';

                    // 处理热更新状态信息
                    if (data.hot_updated && data.hot_updated.length > 0) {
                        message += `，以下配置已立即生效: ${data.hot_updated.join(', ')}`;
                    }

                    // 处理重启提醒
                    if (data.restart_required && data.restart_required.length > 0) {
                        message += `\n⚠️ 重启提醒: ${data.restart_notice}`;
                        showStatus(message, 'info');
                    } else {
                        showStatus(message, 'success');
                    }

                    // 重新加载配置以获取最新状态
                    setTimeout(() => loadConfig(), 1000);
                } else {
                    showStatus(`保存配置失败: ${data.detail || data.error || '未知错误'}`, 'error');
                }
            } catch (error) {
                console.error('saveConfig error:', error);
                showStatus(`网络错误: ${error.message}`, 'error');
            }
        }

        // 环境变量凭证管理相关函数
        async function checkEnvCredsStatus() {
            const envStatusLoading = document.getElementById('envStatusLoading');
            const envStatusContent = document.getElementById('envStatusContent');

            try {
                envStatusLoading.style.display = 'block';
                envStatusContent.classList.add('hidden');

                const response = await fetch('/auth/env-creds-status', {
                    method: 'GET',
                    headers: getAuthHeaders()
                });

                const data = await response.json();

                if (response.ok) {
                    // 更新环境变量列表
                    const envVarsList = document.getElementById('envVarsList');
                    if (Object.keys(data.available_env_vars).length > 0) {
                        envVarsList.textContent = Object.keys(data.available_env_vars).join(', ');
                    } else {
                        envVarsList.textContent = '未找到GCLI_CREDS_*环境变量';
                    }

                    // 更新自动加载状态
                    const autoLoadStatus = document.getElementById('autoLoadStatus');
                    autoLoadStatus.textContent = data.auto_load_enabled ? '✅ 已启用' : '❌ 未启用';
                    autoLoadStatus.style.color = data.auto_load_enabled ? '#28a745' : '#dc3545';

                    // 更新已导入文件统计
                    const envFilesCount = document.getElementById('envFilesCount');
                    envFilesCount.textContent = `${data.existing_env_files_count} 个文件`;

                    const envFilesList = document.getElementById('envFilesList');
                    if (data.existing_env_files.length > 0) {
                        envFilesList.textContent = data.existing_env_files.join(', ');
                    } else {
                        envFilesList.textContent = '无';
                    }

                    envStatusContent.classList.remove('hidden');
                    showStatus('环境变量状态检查完成', 'success');
                } else {
                    showStatus(`获取环境变量状态失败: ${data.detail || data.error || '未知错误'}`, 'error');
                }
            } catch (error) {
                console.error('checkEnvCredsStatus error:', error);
                showStatus(`网络错误: ${error.message}`, 'error');
            } finally {
                envStatusLoading.style.display = 'none';
            }
        }

        async function loadEnvCredentials() {
            try {
                showStatus('正在从环境变量导入凭证...', 'info');

                const response = await fetch('/auth/load-env-creds', {
                    method: 'POST',
                    headers: getAuthHeaders()
                });

                const data = await response.json();

                if (response.ok) {
                    if (data.loaded_count > 0) {
                        showStatus(`✅ 成功导入 ${data.loaded_count}/${data.total_count} 个凭证文件`, 'success');
                        // 刷新状态
                        setTimeout(() => checkEnvCredsStatus(), 1000);
                    } else {
                        showStatus(`⚠️ ${data.message}`, 'info');
                    }
                } else {
                    showStatus(`导入失败: ${data.detail || data.error || '未知错误'}`, 'error');
                }
            } catch (error) {
                console.error('loadEnvCredentials error:', error);
                showStatus(`网络错误: ${error.message}`, 'error');
            }
        }

        async function clearEnvCredentials() {
            if (!confirm('确定要清除所有从环境变量导入的凭证文件吗？\n这将删除所有文件名以 "env-" 开头的认证文件。')) {
                return;
            }

            try {
                showStatus('正在清除环境变量凭证文件...', 'info');

                const response = await fetch('/auth/env-creds', {
                    method: 'DELETE',
                    headers: getAuthHeaders()
                });

                const data = await response.json();

                if (response.ok) {
                    showStatus(`✅ 成功删除 ${data.deleted_count} 个环境变量凭证文件`, 'success');
                    // 刷新状态
                    setTimeout(() => checkEnvCredsStatus(), 1000);
                } else {
                    showStatus(`清除失败: ${data.detail || data.error || '未知错误'}`, 'error');
                }
            } catch (error) {
                console.error('clearEnvCredentials error:', error);
                showStatus(`网络错误: ${error.message}`, 'error');
            }
        }

        // 批量操作相关函数
        function toggleFileSelection(filename) {
            if (selectedCredFiles.has(filename)) {
                selectedCredFiles.delete(filename);
            } else {
                selectedCredFiles.add(filename);
            }
            updateBatchControls();
        }

        function toggleSelectAll() {
            const selectAllCheckbox = document.getElementById('selectAllCheckbox');
            const fileCheckboxes = document.querySelectorAll('.file-checkbox');

            if (selectAllCheckbox.checked) {
                // 全选当前页面的文件
                fileCheckboxes.forEach(checkbox => {
                    const filename = checkbox.getAttribute('data-filename');
                    selectedCredFiles.add(filename);
                    checkbox.checked = true;
                });
            } else {
                // 取消全选
                selectedCredFiles.clear();
                fileCheckboxes.forEach(checkbox => {
                    checkbox.checked = false;
                });
            }
            updateBatchControls();
        }

        function updateBatchControls() {
            const selectedCount = selectedCredFiles.size;
            const selectedCountElement = document.getElementById('selectedCount');
            const batchEnableBtn = document.getElementById('batchEnableBtn');
            const batchDisableBtn = document.getElementById('batchDisableBtn');
            const batchDeleteBtn = document.getElementById('batchDeleteBtn');
            const selectAllCheckbox = document.getElementById('selectAllCheckbox');

            selectedCountElement.textContent = `已选择 ${selectedCount} 项`;

            // 启用/禁用批量操作按钮
            const hasSelection = selectedCount > 0;
            batchEnableBtn.disabled = !hasSelection;
            batchDisableBtn.disabled = !hasSelection;
            batchDeleteBtn.disabled = !hasSelection;

            // 更新全选复选框状态
            const currentPageFileCount = document.querySelectorAll('.file-checkbox').length;
            const currentPageSelectedCount = Array.from(document.querySelectorAll('.file-checkbox'))
                .filter(checkbox => selectedCredFiles.has(checkbox.getAttribute('data-filename'))).length;

            if (currentPageSelectedCount === 0) {
                selectAllCheckbox.indeterminate = false;
                selectAllCheckbox.checked = false;
            } else if (currentPageSelectedCount === currentPageFileCount) {
                selectAllCheckbox.indeterminate = false;
                selectAllCheckbox.checked = true;
            } else {
                selectAllCheckbox.indeterminate = true;
                selectAllCheckbox.checked = false;
            }

            // 更新页面上的复选框状态
            document.querySelectorAll('.file-checkbox').forEach(checkbox => {
                const filename = checkbox.getAttribute('data-filename');
                checkbox.checked = selectedCredFiles.has(filename);
            });
        }

        async function batchAction(action) {
            const selectedFiles = Array.from(selectedCredFiles);

            if (selectedFiles.length === 0) {
                showStatus('请先选择要操作的文件', 'error');
                return;
            }

            let confirmMessage = '';
            switch (action) {
                case 'enable':
                    confirmMessage = `确定要启用选中的 ${selectedFiles.length} 个文件吗？`;
                    break;
                case 'disable':
                    confirmMessage = `确定要禁用选中的 ${selectedFiles.length} 个文件吗？`;
                    break;
                case 'delete':
                    confirmMessage = `确定要删除选中的 ${selectedFiles.length} 个文件吗？\n注意：此操作不可恢复！`;
                    break;
            }

            if (!confirm(confirmMessage)) {
                return;
            }

            try {
                showStatus(`正在执行批量${action === 'enable' ? '启用' : action === 'disable' ? '禁用' : '删除'}操作...`, 'info');

                const requestBody = {
                    action: action,
                    filenames: selectedFiles
                };

                const response = await fetch('/creds/batch-action', {
                    method: 'POST',
                    headers: getAuthHeaders(),
                    body: JSON.stringify(requestBody)
                });

                const data = await response.json();

                if (response.ok) {
                    showStatus(`批量操作完成：成功处理 ${data.success_count}/${selectedFiles.length} 个文件`, 'success');

                    // 清空选择
                    selectedCredFiles.clear();
                    updateBatchControls();

                    // 刷新列表
                    await refreshCredsStatus();
                } else {
                    showStatus(`批量操作失败: ${data.detail || data.error || '未知错误'}`, 'error');
                }
            } catch (error) {
                console.error('batchAction error:', error);
                showStatus(`批量操作网络错误: ${error.message}`, 'error');
            }
        }

        // 邮箱相关函数
        async function fetchUserEmail(filename) {
            try {
                showStatus('正在获取用户邮箱...', 'info');

                const response = await fetch(`/creds/fetch-email/${encodeURIComponent(filename)}`, {
                    method: 'POST',
                    headers: {
                        'Authorization': `Bearer ${authToken}`,
                        'Content-Type': 'application/json'
                    }
                });

                const data = await response.json();

                if (response.ok && data.user_email) {
                    showStatus(`成功获取邮箱: ${data.user_email}`, 'success');
                    // 刷新凭证状态以更新显示
                    await refreshCredsStatus();
                } else {
                    showStatus(data.message || '无法获取用户邮箱', 'error');
                }
            } catch (error) {
                console.error('fetchUserEmail error:', error);
                showStatus(`获取邮箱失败: ${error.message}`, 'error');
            }
        }

        async function refreshAllEmails() {
            try {
                if (!confirm('确定要刷新所有凭证的用户邮箱吗？这可能需要一些时间。')) {
                    return;
                }

                showStatus('正在刷新所有用户邮箱...', 'info');

                const response = await fetch('/creds/refresh-all-emails', {
                    method: 'POST',
                    headers: {
                        'Authorization': `Bearer ${authToken}`,
                        'Content-Type': 'application/json'
                    }
                });

                const data = await response.json();

                if (response.ok) {
                    showStatus(`邮箱刷新完成：成功获取 ${data.success_count}/${data.total_count} 个邮箱地址`, 'success');
                    // 刷新凭证状态以更新显示
                    await refreshCredsStatus();
                } else {
                    showStatus(data.message || '邮箱刷新失败', 'error');
                }
            } catch (error) {
                console.error('refreshAllEmails error:', error);
                showStatus(`邮箱刷新网络错误: ${error.message}`, 'error');
            }
        }

        // Project ID 折叠切换函数
        function toggleProjectIdSection() {
            const section = document.getElementById('projectIdSection');
            const icon = document.getElementById('projectIdToggleIcon');

            if (section.style.display === 'none') {
                section.style.display = 'block';
                icon.style.transform = 'rotate(90deg)';
                icon.textContent = '▼';
            } else {
                section.style.display = 'none';
                icon.style.transform = 'rotate(0deg)';
                icon.textContent = '▶';
            }
        }

        // 回调URL输入区域折叠切换函数
        function toggleCallbackUrlSection() {
            const section = document.getElementById('callbackUrlSection');
            const icon = document.getElementById('callbackUrlToggleIcon');

            if (section.style.display === 'none') {
                section.style.display = 'block';
                icon.style.transform = 'rotate(180deg)';
                icon.textContent = '▲';
            } else {
                section.style.display = 'none';
                icon.style.transform = 'rotate(0deg)';
                icon.textContent = '▼';
            }
        }

        // 处理回调URL的函数
        async function processCallbackUrl() {
            const callbackUrlInput = document.getElementById('callbackUrlInput');
            const callbackUrl = callbackUrlInput.value.trim();
            const getAllProjects = document.getElementById('getAllProjectsCreds').checked;

            if (!callbackUrl) {
                showStatus('请输入回调URL', 'error');
                return;
            }

            // 简单验证URL格式
            if (!callbackUrl.startsWith('http://') && !callbackUrl.startsWith('https://')) {
                showStatus('请输入有效的URL（以http://或https://开头）', 'error');
                return;
            }

            // 检查是否包含必要参数
            if (!callbackUrl.includes('code=') || !callbackUrl.includes('state=')) {
                showStatus('❌ 这不是有效的回调URL！请确保：\n1. 已完成Google OAuth授权\n2. 复制的是浏览器地址栏的完整URL\n3. URL包含code和state参数', 'error');
                return;
            }

            if (getAllProjects) {
                showStatus('正在从回调URL并发批量获取所有项目凭证...', 'info');
            } else {
                showStatus('正在从回调URL获取凭证...', 'info');
            }

            try {
                // 获取当前项目ID设置（如果有的话）
                const projectIdInput = document.getElementById('projectId');
                const projectId = projectIdInput ? projectIdInput.value.trim() : null;

                const response = await fetch('/auth/callback-url', {
                    method: 'POST',
                    headers: getAuthHeaders(),
                    body: JSON.stringify({
                        callback_url: callbackUrl,
                        project_id: projectId || null,
                        get_all_projects: getAllProjects
                    })
                });

                const result = await response.json();

                if (getAllProjects && result.multiple_credentials) {
                    // 处理多项目认证结果
                    const results = result.multiple_credentials;
                    let resultText = `批量并发认证完成！成功为 ${results.success.length} 个项目生成凭证：\n\n`;

                    // 显示成功的项目
                    results.success.forEach((item, index) => {
                        resultText += `${index + 1}. 项目: ${item.project_name} (${item.project_id})\n`;
                        resultText += `   文件: ${item.file_path}\n\n`;
                    });

                    // 显示失败的项目（如果有）
                    if (results.failed.length > 0) {
                        resultText += `\n失败的项目 (${results.failed.length} 个):\n`;
                        results.failed.forEach((item, index) => {
                            resultText += `${index + 1}. 项目: ${item.project_name} (${item.project_id})\n`;
                            resultText += `   错误: ${item.error}\n\n`;
                        });
                    }

                    // 显示结果
                    document.getElementById('credentialsContent').textContent = resultText;
                    document.getElementById('credentialsSection').classList.remove('hidden');
                    showStatus(`✅ 批量并发认证完成！成功生成 ${results.success.length} 个项目的凭证文件${results.failed.length > 0 ? `，${results.failed.length} 个项目失败` : ''}`, 'success');

                } else if (result.credentials) {
                    // 处理单项目认证结果
                    showStatus(result.message || '从回调URL获取凭证成功！', 'success');

                    // 显示凭证内容
                    document.getElementById('credentialsContent').innerHTML =
                        '<pre>' + JSON.stringify(result.credentials, null, 2) + '</pre>';
                    document.getElementById('credentialsSection').classList.remove('hidden');

                } else if (result.requires_manual_project_id) {
                    showStatus('需要手动指定项目ID，请在高级选项中填入Google Cloud项目ID后重试', 'error');
                } else if (result.requires_project_selection) {
                    let projectOptions = '<br><strong>可用项目：</strong><br>';
                    result.available_projects.forEach(project => {
                        projectOptions += `• ${project.name} (ID: ${project.projectId})<br>`;
                    });
                    showStatus('检测到多个项目，请在高级选项中指定项目ID：' + projectOptions, 'error');
                } else {
                    showStatus(result.error || '从回调URL获取凭证失败', 'error');
                }

                // 清空输入框
                callbackUrlInput.value = '';

                // 刷新凭证列表（如果有）
                setTimeout(() => {
                    if (typeof refreshCredsStatus === 'function') {
                        refreshCredsStatus();
                    }
                }, 1000);

            } catch (error) {
                console.error('从回调URL获取凭证时出错:', error);
                showStatus(`从回调URL获取凭证失败: ${error.message}`, 'error');
            }
        }

        // 处理勾选框状态变化
        function handleGetAllProjectsChange() {
            const checkbox = document.getElementById('getAllProjectsCreds');
            const note = document.getElementById('allProjectsNote');
            const projectIdSection = document.getElementById('projectIdSection');
            const projectIdToggle = document.querySelector('[onclick="toggleProjectIdSection()"]');

            if (checkbox.checked) {
                // 显示批量认证提示
                note.style.display = 'block';
                // 禁用项目ID输入（批量模式下不需要指定单个项目）
                if (projectIdSection.style.display !== 'none') {
                    toggleProjectIdSection();
                }
                projectIdToggle.style.opacity = '0.5';
                projectIdToggle.style.pointerEvents = 'none';
                projectIdToggle.title = '批量认证模式下无需指定单个项目ID';
            } else {
                // 隐藏批量认证提示
                note.style.display = 'none';
                // 重新启用项目ID输入
                projectIdToggle.style.opacity = '1';
                projectIdToggle.style.pointerEvents = 'auto';
                projectIdToggle.title = '';
            }
        }

        // 页面加载时检查状态
        window.onload = function () {
            console.log('Page loaded');
            console.log('Login section exists:', !!document.getElementById('loginSection'));
            console.log('Main section exists:', !!document.getElementById('mainSection'));
            console.log('Status section exists:', !!document.getElementById('statusSection'));

            // 添加勾选框事件监听器
            const checkbox = document.getElementById('getAllProjectsCreds');
            if (checkbox) {
                checkbox.addEventListener('change', handleGetAllProjectsChange);
            }

            showStatus('请输入密码登录', 'info');
        };

        // =====================================================================
        // 使用统计相关函数
        // =====================================================================

        let usageStatsData = {};
        let currentEditingFile = '';

        // 刷新使用统计
        async function refreshUsageStats() {
            const usageLoading = document.getElementById('usageLoading');
            const usageList = document.getElementById('usageList');

            try {
                usageLoading.style.display = 'block';
                usageList.innerHTML = '';

                // 获取所有文件的使用统计
                const [statsResponse, aggregatedResponse] = await Promise.all([
                    fetch('/usage/stats', {
                        method: 'GET',
                        headers: getAuthHeaders()
                    }),
                    fetch('/usage/aggregated', {
                        method: 'GET',
                        headers: getAuthHeaders()
                    })
                ]);

                const statsData = await statsResponse.json();
                const aggregatedData = await aggregatedResponse.json();

                if (statsResponse.ok && aggregatedResponse.ok) {
                    usageStatsData = statsData.data;

                    // 更新概览统计
                    document.getElementById('totalApiCalls').textContent = aggregatedData.data.total_all_model_calls || 0;
                    document.getElementById('geminiProCalls').textContent = aggregatedData.data.total_gemini_2_5_pro_calls || 0;
                    document.getElementById('totalFiles').textContent = aggregatedData.data.total_files || 0;

                    // 渲染使用统计列表
                    renderUsageList();

                    showStatus(`已加载 ${aggregatedData.data.total_files} 个文件的使用统计`, 'success');
                } else {
                    showStatus('加载使用统计失败', 'error');
                }
            } catch (error) {
                console.error('refreshUsageStats error:', error);
                showStatus(`网络错误: ${error.message}`, 'error');
            } finally {
                usageLoading.style.display = 'none';
            }
        }

        // 渲染使用统计列表
        function renderUsageList() {
            const usageList = document.getElementById('usageList');
            usageList.innerHTML = '';

            if (Object.keys(usageStatsData).length === 0) {
                usageList.innerHTML = '<p style="text-align: center; color: #666;">暂无使用统计数据</p>';
                return;
            }

            for (const [filename, stats] of Object.entries(usageStatsData)) {
                const card = createUsageCard(filename, stats);
                usageList.appendChild(card);
            }
        }

        // 创建使用统计卡片
        function createUsageCard(filename, stats) {
            const div = document.createElement('div');
            div.className = 'usage-card';

            // 计算使用百分比
            const geminiPercent = Math.min((stats.gemini_2_5_pro_calls / stats.daily_limit_gemini_2_5_pro) * 100, 100);
            const totalPercent = Math.min((stats.total_calls / stats.daily_limit_total) * 100, 100);

            // 确定进度条颜色
            function getProgressClass(percent) {
                if (percent >= 90) return 'danger';
                if (percent >= 70) return 'warning';
                return 'gemini';
            }

            function getTotalProgressClass(percent) {
                if (percent >= 90) return 'danger';
                if (percent >= 70) return 'warning';
                return 'total';
            }

            // 格式化时间
            function formatTime(isoString) {
                if (!isoString) return '未知';
                try {
                    const date = new Date(isoString);
                    return date.toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' });
                } catch (e) {
                    return '格式错误';
                }
            }

            div.innerHTML = `
                <div class="usage-header">
                    <div class="usage-filename">${filename}</div>
                </div>
                
                <div class="usage-progress">
                    <div class="usage-progress-label">
                        <span>Gemini 2.5 Pro</span>
                        <span>${stats.gemini_2_5_pro_calls}/${stats.daily_limit_gemini_2_5_pro} (${geminiPercent.toFixed(1)}%)</span>
                    </div>
                    <div class="usage-progress-bar">
                        <div class="usage-progress-fill ${getProgressClass(geminiPercent)}" style="width: ${geminiPercent}%"></div>
                    </div>
                </div>
                
                <div class="usage-progress">
                    <div class="usage-progress-label">
                        <span>所有模型</span>
                        <span>${stats.total_calls}/${stats.daily_limit_total} (${totalPercent.toFixed(1)}%)</span>
                    </div>
                    <div class="usage-progress-bar">
                        <div class="usage-progress-fill ${getTotalProgressClass(totalPercent)}" style="width: ${totalPercent}%"></div>
                    </div>
                </div>
                
                <div class="usage-info">
                    <div class="usage-info-item" style="grid-column: 1 / -1;">
                        <span class="usage-info-label">下次重置时间</span>
                        <span class="usage-info-value">${formatTime(stats.next_reset_time)}</span>
                    </div>
                </div>
                
                <div class="usage-actions">
                    <button class="usage-btn limits" onclick="openLimitsModal('${filename}')">设置限制</button>
                    <button class="usage-btn reset" onclick="resetSingleUsageStats('${filename}')">重置统计</button>
                </div>
            `;

            return div;
        }

        // 打开限制设置弹窗
        function openLimitsModal(filename) {
            const stats = usageStatsData[filename];
            if (!stats) {
                showStatus('找不到文件统计数据', 'error');
                return;
            }

            currentEditingFile = filename;
            document.getElementById('modalFilename').value = filename;
            document.getElementById('modalGeminiLimit').value = stats.daily_limit_gemini_2_5_pro;
            document.getElementById('modalTotalLimit').value = stats.daily_limit_total;
            document.getElementById('limitsModal').style.display = 'block';
        }

        // 关闭限制设置弹窗
        function closeLimitsModal() {
            document.getElementById('limitsModal').style.display = 'none';
            currentEditingFile = '';
        }

        // 保存限制设置
        async function saveLimits() {
            const geminiLimit = parseInt(document.getElementById('modalGeminiLimit').value);
            const totalLimit = parseInt(document.getElementById('modalTotalLimit').value);

            if (isNaN(geminiLimit) || geminiLimit < 1) {
                showStatus('Gemini 2.5 Pro 限制必须是大于0的数字', 'error');
                return;
            }

            if (isNaN(totalLimit) || totalLimit < 1) {
                showStatus('总调用限制必须是大于0的数字', 'error');
                return;
            }

            try {
                const response = await fetch('/usage/update-limits', {
                    method: 'POST',
                    headers: getAuthHeaders(),
                    body: JSON.stringify({
                        filename: currentEditingFile,
                        gemini_2_5_pro_limit: geminiLimit,
                        total_limit: totalLimit
                    })
                });

                const data = await response.json();

                if (response.ok) {
                    showStatus(data.message, 'success');
                    closeLimitsModal();
                    // 刷新统计数据
                    await refreshUsageStats();
                } else {
                    showStatus(`设置失败: ${data.detail || data.error || '未知错误'}`, 'error');
                }
            } catch (error) {
                console.error('saveLimits error:', error);
                showStatus(`网络错误: ${error.message}`, 'error');
            }
        }

        // 重置单个文件的使用统计
        async function resetSingleUsageStats(filename) {
            if (!confirm(`确定要重置 ${filename} 的使用统计吗？`)) {
                return;
            }

            try {
                const response = await fetch('/usage/reset', {
                    method: 'POST',
                    headers: getAuthHeaders(),
                    body: JSON.stringify({ filename: filename })
                });

                const data = await response.json();

                if (response.ok) {
                    showStatus(data.message, 'success');
                    await refreshUsageStats();
                } else {
                    showStatus(`重置失败: ${data.detail || data.error || '未知错误'}`, 'error');
                }
            } catch (error) {
                console.error('resetSingleUsageStats error:', error);
                showStatus(`网络错误: ${error.message}`, 'error');
            }
        }

        // 重置所有使用统计
        async function resetAllUsageStats() {
            if (!confirm('确定要重置所有文件的使用统计吗？此操作不可恢复！')) {
                return;
            }

            try {
                const response = await fetch('/usage/reset', {
                    method: 'POST',
                    headers: getAuthHeaders(),
                    body: JSON.stringify({})  // 不提供filename表示重置所有
                });

                const data = await response.json();

                if (response.ok) {
                    showStatus(data.message, 'success');
                    await refreshUsageStats();
                } else {
                    showStatus(`重置失败: ${data.detail || data.error || '未知错误'}`, 'error');
                }
            } catch (error) {
                console.error('resetAllUsageStats error:', error);
                showStatus(`网络错误: ${error.message}`, 'error');
            }
        }

        // 关闭弹窗当点击弹窗外部时
        window.onclick = function (event) {
            const modal = document.getElementById('limitsModal');
            if (event.target == modal) {
                closeLimitsModal();
            }
        }

        // =====================================================================
        // 端点配置快速切换函数
        // =====================================================================

        // 镜像网址配置
        const mirrorUrls = {
            codeAssistEndpoint: 'https://gcli-api.sukaka.top/cloudcode-pa',
            oauthProxyUrl: 'https://gcli-api.sukaka.top/oauth2',
            googleapisProxyUrl: 'https://gcli-api.sukaka.top/googleapis',
            resourceManagerApiUrl: 'https://gcli-api.sukaka.top/cloudresourcemanager',
            serviceUsageApiUrl: 'https://gcli-api.sukaka.top/serviceusage'
        };

        // 官方端点配置
        const officialUrls = {
            codeAssistEndpoint: 'https://cloudcode-pa.googleapis.com',
            oauthProxyUrl: 'https://oauth2.googleapis.com',
            googleapisProxyUrl: 'https://www.googleapis.com',
            resourceManagerApiUrl: 'https://cloudresourcemanager.googleapis.com',
            serviceUsageApiUrl: 'https://serviceusage.googleapis.com'
        };

        // 使用镜像网址
        function useMirrorUrls() {
            if (confirm('确定要将所有端点配置为镜像网址吗？\n\n镜像网址：\n• Code Assist: https://gcli-api.sukaka.top/cloudcode-pa\n• OAuth: https://gcli-api.sukaka.top/oauth2\n• Google APIs: https://gcli-api.sukaka.top/googleapis\n• Resource Manager: https://gcli-api.sukaka.top/cloudresourcemanager\n• Service Usage: https://gcli-api.sukaka.top/serviceusage')) {

                // 设置所有端点为镜像网址
                for (const [fieldId, url] of Object.entries(mirrorUrls)) {
                    const field = document.getElementById(fieldId);
                    if (field && !field.disabled) {
                        field.value = url;
                    }
                }

                showStatus('✅ 已切换到镜像网址配置，记得点击"保存配置"按钮保存设置', 'success');
            }
        }

        // 还原官方端点
        function restoreOfficialUrls() {
            if (confirm('确定要将所有端点配置为官方地址吗？\n\n官方端点：\n• Code Assist: https://cloudcode-pa.googleapis.com\n• OAuth: https://oauth2.googleapis.com\n• Google APIs: https://www.googleapis.com\n• Resource Manager: https://cloudresourcemanager.googleapis.com\n• Service Usage: https://serviceusage.googleapis.com')) {

                // 设置所有端点为官方地址
                for (const [fieldId, url] of Object.entries(officialUrls)) {
                    const field = document.getElementById(fieldId);
                    if (field && !field.disabled) {
                        field.value = url;
                    }
                }

                showStatus('✅ 已切换到官方端点配置，记得点击"保存配置"按钮保存设置', 'success');
            }
        }
    </script>
</body>

</html>